@loaders.gl/tiles 3.1.7 → 3.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.
- package/dist/dist.min.js +302 -318
- package/dist/es5/tileset/helpers/frame-state.js +79 -0
- package/dist/es5/tileset/helpers/frame-state.js.map +1 -1
- package/dist/es5/tileset/helpers/i3s-lod.js +17 -26
- package/dist/es5/tileset/helpers/i3s-lod.js.map +1 -1
- package/dist/es5/tileset/helpers/zoom.js +32 -0
- package/dist/es5/tileset/helpers/zoom.js.map +1 -1
- package/dist/es5/tileset/tile-3d.js +5 -0
- package/dist/es5/tileset/tile-3d.js.map +1 -1
- package/dist/es5/tileset/tileset-3d.js +244 -85
- package/dist/es5/tileset/tileset-3d.js.map +1 -1
- package/dist/es5/tileset/traversers/i3s-frame-counter.js +45 -0
- package/dist/es5/tileset/traversers/i3s-frame-counter.js.map +1 -0
- package/dist/es5/tileset/traversers/i3s-tile-manager.js +17 -0
- package/dist/es5/tileset/traversers/i3s-tile-manager.js.map +1 -1
- package/dist/es5/tileset/traversers/i3s-tileset-traverser.js +6 -1
- package/dist/es5/tileset/traversers/i3s-tileset-traverser.js.map +1 -1
- package/dist/es5/tileset/traversers/tileset-traverser.js +13 -1
- package/dist/es5/tileset/traversers/tileset-traverser.js.map +1 -1
- package/dist/esm/tileset/helpers/frame-state.js +52 -0
- package/dist/esm/tileset/helpers/frame-state.js.map +1 -1
- package/dist/esm/tileset/helpers/i3s-lod.js +17 -27
- package/dist/esm/tileset/helpers/i3s-lod.js.map +1 -1
- package/dist/esm/tileset/helpers/zoom.js +17 -0
- package/dist/esm/tileset/helpers/zoom.js.map +1 -1
- package/dist/esm/tileset/tile-3d.js +4 -0
- package/dist/esm/tileset/tile-3d.js.map +1 -1
- package/dist/esm/tileset/tileset-3d.js +95 -17
- package/dist/esm/tileset/tileset-3d.js.map +1 -1
- package/dist/esm/tileset/traversers/i3s-frame-counter.js +23 -0
- package/dist/esm/tileset/traversers/i3s-frame-counter.js.map +1 -0
- package/dist/esm/tileset/traversers/i3s-tile-manager.js +15 -0
- package/dist/esm/tileset/traversers/i3s-tile-manager.js.map +1 -1
- package/dist/esm/tileset/traversers/i3s-tileset-traverser.js +5 -1
- package/dist/esm/tileset/traversers/i3s-tileset-traverser.js.map +1 -1
- package/dist/esm/tileset/traversers/tileset-traverser.js +14 -1
- package/dist/esm/tileset/traversers/tileset-traverser.js.map +1 -1
- package/dist/tileset/helpers/frame-state.d.ts +14 -0
- package/dist/tileset/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset/helpers/frame-state.js +49 -1
- package/dist/tileset/helpers/i3s-lod.d.ts.map +1 -1
- package/dist/tileset/helpers/i3s-lod.js +17 -16
- package/dist/tileset/helpers/zoom.d.ts +35 -0
- package/dist/tileset/helpers/zoom.d.ts.map +1 -1
- package/dist/tileset/helpers/zoom.js +41 -1
- package/dist/tileset/tile-3d.d.ts +5 -0
- package/dist/tileset/tile-3d.d.ts.map +1 -1
- package/dist/tileset/tile-3d.js +7 -0
- package/dist/tileset/tileset-3d.d.ts +36 -4
- package/dist/tileset/tileset-3d.d.ts.map +1 -1
- package/dist/tileset/tileset-3d.js +99 -20
- package/dist/tileset/traversers/i3s-frame-counter.d.ts +24 -0
- package/dist/tileset/traversers/i3s-frame-counter.d.ts.map +1 -0
- package/dist/tileset/traversers/i3s-frame-counter.js +37 -0
- package/dist/tileset/traversers/i3s-tile-manager.d.ts +10 -2
- package/dist/tileset/traversers/i3s-tile-manager.d.ts.map +1 -1
- package/dist/tileset/traversers/i3s-tile-manager.js +24 -0
- package/dist/tileset/traversers/i3s-tileset-traverser.d.ts +9 -2
- package/dist/tileset/traversers/i3s-tileset-traverser.d.ts.map +1 -1
- package/dist/tileset/traversers/i3s-tileset-traverser.js +10 -1
- package/dist/tileset/traversers/tileset-traverser.d.ts +5 -1
- package/dist/tileset/traversers/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset/traversers/tileset-traverser.js +10 -1
- package/package.json +5 -5
- package/src/tileset/helpers/frame-state.ts +56 -0
- package/src/tileset/helpers/i3s-lod.ts +18 -19
- package/src/tileset/helpers/zoom.ts +64 -0
- package/src/tileset/tile-3d.ts +8 -0
- package/src/tileset/tileset-3d.ts +123 -21
- package/src/tileset/traversers/i3s-frame-counter.ts +35 -0
- package/src/tileset/traversers/i3s-tile-manager.ts +26 -2
- package/src/tileset/traversers/i3s-tileset-traverser.ts +16 -3
- package/src/tileset/traversers/tileset-traverser.ts +13 -2
|
@@ -3,6 +3,14 @@ import {Ellipsoid} from '@math.gl/geospatial';
|
|
|
3
3
|
import Tile3D from '../tile-3d';
|
|
4
4
|
import {FrameState} from './frame-state';
|
|
5
5
|
|
|
6
|
+
const cameraPositionCartesian = new Vector3();
|
|
7
|
+
const toEye = new Vector3();
|
|
8
|
+
const cameraPositionEnu = new Vector3();
|
|
9
|
+
const extraVertexEnu = new Vector3();
|
|
10
|
+
const projectedOriginVector = new Vector3();
|
|
11
|
+
const enuToCartesianMatrix = new Matrix4();
|
|
12
|
+
const cartesianToEnuMatrix = new Matrix4();
|
|
13
|
+
|
|
6
14
|
/**
|
|
7
15
|
* For the maxScreenThreshold error metric, maxError means that you should replace the node with it's children
|
|
8
16
|
as soon as the nodes bounding sphere has a screen radius larger than maxError pixels.
|
|
@@ -36,45 +44,35 @@ export function getLodStatus(tile: Tile3D, frameState: FrameState): 'DIG' | 'OUT
|
|
|
36
44
|
*/
|
|
37
45
|
// eslint-disable-next-line max-statements
|
|
38
46
|
export function getProjectedRadius(tile: Tile3D, frameState: FrameState): number {
|
|
39
|
-
const
|
|
40
|
-
const ViewportClass = originalViewport.constructor;
|
|
41
|
-
const {longitude, latitude, height, width, bearing, zoom} = originalViewport;
|
|
42
|
-
// @ts-ignore
|
|
43
|
-
const viewport = new ViewportClass({longitude, latitude, height, width, bearing, zoom, pitch: 0});
|
|
47
|
+
const {topDownViewport: viewport} = frameState;
|
|
44
48
|
const mbsLat = tile.header.mbs[1];
|
|
45
49
|
const mbsLon = tile.header.mbs[0];
|
|
46
50
|
const mbsZ = tile.header.mbs[2];
|
|
47
51
|
const mbsR = tile.header.mbs[3];
|
|
48
52
|
const mbsCenterCartesian = [...tile.boundingVolume.center];
|
|
49
53
|
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
50
|
-
|
|
51
|
-
cameraPositionCartographic,
|
|
52
|
-
new Vector3()
|
|
53
|
-
);
|
|
54
|
+
Ellipsoid.WGS84.cartographicToCartesian(cameraPositionCartographic, cameraPositionCartesian);
|
|
54
55
|
|
|
55
56
|
// ---------------------------
|
|
56
57
|
// Calculate mbs border vertex
|
|
57
58
|
// ---------------------------
|
|
58
|
-
|
|
59
|
+
toEye.copy(cameraPositionCartesian).subtract(mbsCenterCartesian).normalize();
|
|
59
60
|
// Add extra vector to form plane
|
|
60
|
-
const enuToCartesianMatrix = new Matrix4();
|
|
61
61
|
Ellipsoid.WGS84.eastNorthUpToFixedFrame(mbsCenterCartesian, enuToCartesianMatrix);
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
cartesianToEnuMatrix.copy(enuToCartesianMatrix).invert();
|
|
63
|
+
cameraPositionEnu.copy(cameraPositionCartesian).transform(cartesianToEnuMatrix);
|
|
64
64
|
// Mean Proportionals in Right Triangles - Altitude rule
|
|
65
65
|
// https://mathbitsnotebook.com/Geometry/RightTriangles/RTmeanRight.html
|
|
66
66
|
const projection = Math.sqrt(
|
|
67
67
|
cameraPositionEnu[0] * cameraPositionEnu[0] + cameraPositionEnu[1] * cameraPositionEnu[1]
|
|
68
68
|
);
|
|
69
69
|
const extraZ = (projection * projection) / cameraPositionEnu[2];
|
|
70
|
-
|
|
70
|
+
extraVertexEnu.copy([cameraPositionEnu[0], cameraPositionEnu[1], extraZ]);
|
|
71
71
|
const extraVertexCartesian = extraVertexEnu.transform(enuToCartesianMatrix);
|
|
72
|
-
const extraVectorCartesian =
|
|
73
|
-
.subtract(mbsCenterCartesian)
|
|
74
|
-
.normalize();
|
|
72
|
+
const extraVectorCartesian = extraVertexCartesian.subtract(mbsCenterCartesian).normalize();
|
|
75
73
|
// We need radius vector orthogonal to toEye vector
|
|
76
74
|
const radiusVector = toEye.cross(extraVectorCartesian).normalize().scale(mbsR);
|
|
77
|
-
const sphereMbsBorderVertexCartesian =
|
|
75
|
+
const sphereMbsBorderVertexCartesian = radiusVector.add(mbsCenterCartesian);
|
|
78
76
|
const sphereMbsBorderVertexCartographic = Ellipsoid.WGS84.cartesianToCartographic(
|
|
79
77
|
sphereMbsBorderVertexCartesian
|
|
80
78
|
);
|
|
@@ -83,7 +81,8 @@ export function getProjectedRadius(tile: Tile3D, frameState: FrameState): number
|
|
|
83
81
|
// Project center vertex and border vertex and calculate projected radius of MBS
|
|
84
82
|
const projectedOrigin = viewport.project([mbsLon, mbsLat, mbsZ]);
|
|
85
83
|
const projectedMbsBorderVertex = viewport.project(sphereMbsBorderVertexCartographic);
|
|
86
|
-
const projectedRadius =
|
|
84
|
+
const projectedRadius = projectedOriginVector
|
|
85
|
+
.copy(projectedOrigin)
|
|
87
86
|
.subtract(projectedMbsBorderVertex)
|
|
88
87
|
.magnitude();
|
|
89
88
|
return projectedRadius;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Vector3} from '@math.gl/core';
|
|
2
2
|
import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
|
|
3
|
+
import {Ellipsoid} from '@math.gl/geospatial';
|
|
3
4
|
import {BoundingRectangle} from '../../types';
|
|
4
5
|
|
|
5
6
|
const WGS84_RADIUS_X = 6378137.0;
|
|
@@ -42,6 +43,69 @@ export function getZoomFromBoundingVolume(
|
|
|
42
43
|
return 1;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Calculate initial zoom for the tileset from 3D `fullExtent` defined in
|
|
48
|
+
* the tileset metadata
|
|
49
|
+
* @param fullExtent - 3D extent of the tileset
|
|
50
|
+
* @param fullExtent.xmin - minimal longitude in decimal degrees
|
|
51
|
+
* @param fullExtent.xmax - maximal longitude in decimal degrees
|
|
52
|
+
* @param fullExtent.ymin - minimal latitude in decimal degrees
|
|
53
|
+
* @param fullExtent.ymax - maximal latitude in decimal degrees
|
|
54
|
+
* @param fullExtent.zmin - minimal elevation in meters
|
|
55
|
+
* @param fullExtent.zmax - maximal elevation in meters
|
|
56
|
+
* @param cartorgraphicCenter - tileset center in cartographic coordinate system
|
|
57
|
+
* @param cartesianCenter - tileset center in cartesian coordinate system
|
|
58
|
+
* @returns - initial zoom for the tileset
|
|
59
|
+
*/
|
|
60
|
+
export function getZoomFromFullExtent(
|
|
61
|
+
fullExtent: {
|
|
62
|
+
xmin: number;
|
|
63
|
+
xmax: number;
|
|
64
|
+
ymin: number;
|
|
65
|
+
ymax: number;
|
|
66
|
+
zmin: number;
|
|
67
|
+
zmax: number;
|
|
68
|
+
},
|
|
69
|
+
cartorgraphicCenter: Vector3,
|
|
70
|
+
cartesianCenter: Vector3
|
|
71
|
+
) {
|
|
72
|
+
const extentVertex = Ellipsoid.WGS84.cartographicToCartesian(
|
|
73
|
+
[fullExtent.xmax, fullExtent.ymax, fullExtent.zmax],
|
|
74
|
+
new Vector3()
|
|
75
|
+
);
|
|
76
|
+
const extentSize = Math.sqrt(
|
|
77
|
+
Math.pow(extentVertex[0] - cartesianCenter[0], 2) +
|
|
78
|
+
Math.pow(extentVertex[1] - cartesianCenter[1], 2) +
|
|
79
|
+
Math.pow(extentVertex[2] - cartesianCenter[2], 2)
|
|
80
|
+
);
|
|
81
|
+
return Math.log2(WGS84_RADIUS_Z / (extentSize + cartorgraphicCenter[2]));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Calculate initial zoom for the tileset from 2D `extent` defined in
|
|
86
|
+
* the tileset metadata
|
|
87
|
+
* @param extent - 2D extent of the tileset. It is array of 4 elements [xmin, ymin, xmax, ymax]
|
|
88
|
+
* @param extent[0] - minimal longitude in decimal degrees
|
|
89
|
+
* @param extent[1] - minimal latitude in decimal degrees
|
|
90
|
+
* @param extent[2] - maximal longitude in decimal degrees
|
|
91
|
+
* @param extent[3] - maximal latitude in decimal degrees
|
|
92
|
+
* @param cartorgraphicCenter - tileset center in cartographic coordinate system
|
|
93
|
+
* @param cartesianCenter - tileset center in cartesian coordinate system
|
|
94
|
+
* @returns - initial zoom for the tileset
|
|
95
|
+
*/
|
|
96
|
+
export function getZoomFromExtent(
|
|
97
|
+
extent: [number, number, number, number],
|
|
98
|
+
cartorgraphicCenter: Vector3,
|
|
99
|
+
cartesianCenter: Vector3
|
|
100
|
+
) {
|
|
101
|
+
const [xmin, ymin, xmax, ymax] = extent;
|
|
102
|
+
return getZoomFromFullExtent(
|
|
103
|
+
{xmin, xmax, ymin, ymax, zmin: 0, zmax: 0},
|
|
104
|
+
cartorgraphicCenter,
|
|
105
|
+
cartesianCenter
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
45
109
|
function getObbSize(halfAxes) {
|
|
46
110
|
halfAxes.getColumn(0, scratchVector);
|
|
47
111
|
const axeY = halfAxes.getColumn(1);
|
package/src/tileset/tile-3d.ts
CHANGED
|
@@ -298,6 +298,14 @@ export default class TileHeader {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Make tile unselected than means it won't be shown
|
|
303
|
+
* but it can be still loaded in memory
|
|
304
|
+
*/
|
|
305
|
+
unselect(): void {
|
|
306
|
+
this._selectedFrame = 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
301
309
|
/*
|
|
302
310
|
* If skipLevelOfDetail is off try to load child tiles as soon as possible so that their parent can refine sooner.
|
|
303
311
|
* Tiles are prioritized by screen space error.
|
|
@@ -48,8 +48,8 @@ import {
|
|
|
48
48
|
} from '@loaders.gl/loader-utils';
|
|
49
49
|
import TilesetCache from './tileset-cache';
|
|
50
50
|
import {calculateTransformProps} from './helpers/transform-utils';
|
|
51
|
-
import {FrameState, getFrameState} from './helpers/frame-state';
|
|
52
|
-
import {getZoomFromBoundingVolume} from './helpers/zoom';
|
|
51
|
+
import {FrameState, getFrameState, limitSelectedTiles} from './helpers/frame-state';
|
|
52
|
+
import {getZoomFromBoundingVolume, getZoomFromExtent, getZoomFromFullExtent} from './helpers/zoom';
|
|
53
53
|
import Tile3D from './tile-3d';
|
|
54
54
|
import Tileset3DTraverser from './traversers/tileset-3d-traverser';
|
|
55
55
|
import TilesetTraverser from './traversers/tileset-traverser';
|
|
@@ -64,6 +64,8 @@ export type Tileset3DProps = {
|
|
|
64
64
|
loadTiles?: boolean;
|
|
65
65
|
basePath?: string;
|
|
66
66
|
maximumMemoryUsage?: number;
|
|
67
|
+
maximumTilesSelected?: number;
|
|
68
|
+
debounceTime?: number;
|
|
67
69
|
|
|
68
70
|
// Metadata
|
|
69
71
|
description?: string;
|
|
@@ -93,6 +95,8 @@ type Props = {
|
|
|
93
95
|
modelMatrix: Matrix4;
|
|
94
96
|
throttleRequests: boolean;
|
|
95
97
|
maximumMemoryUsage: number;
|
|
98
|
+
maximumTilesSelected: number;
|
|
99
|
+
debounceTime: number;
|
|
96
100
|
onTileLoad: (tile: Tile3D) => any;
|
|
97
101
|
onTileUnload: (tile: Tile3D) => any;
|
|
98
102
|
onTileError: (tile: Tile3D, message: string, url: string) => any;
|
|
@@ -124,6 +128,10 @@ const DEFAULT_PROPS: Props = {
|
|
|
124
128
|
maxRequests: 64,
|
|
125
129
|
|
|
126
130
|
maximumMemoryUsage: 32,
|
|
131
|
+
/** Maximum number limit of tiles selected for show. 0 means no limit */
|
|
132
|
+
maximumTilesSelected: 0,
|
|
133
|
+
/** Delay time before the tileset traversal. It prevents traversal requests spam.*/
|
|
134
|
+
debounceTime: 0,
|
|
127
135
|
|
|
128
136
|
/**
|
|
129
137
|
* Callback. Indicates this a tile's content was loaded
|
|
@@ -149,7 +157,6 @@ const DEFAULT_PROPS: Props = {
|
|
|
149
157
|
// View distance scale modifier
|
|
150
158
|
viewDistanceScale: 1.0,
|
|
151
159
|
|
|
152
|
-
// TODO CESIUM
|
|
153
160
|
// The maximum screen space error used to drive level of detail refinement.
|
|
154
161
|
maximumScreenSpaceError: 8,
|
|
155
162
|
|
|
@@ -207,6 +214,8 @@ export default class Tileset3D {
|
|
|
207
214
|
traverseCounter: number;
|
|
208
215
|
geometricError: number;
|
|
209
216
|
selectedTiles: Tile3D[];
|
|
217
|
+
private updatePromise: Promise<number> | null = null;
|
|
218
|
+
tilesetInitializationPromise: Promise<void>;
|
|
210
219
|
|
|
211
220
|
cartographicCenter: Vector3 | null;
|
|
212
221
|
cartesianCenter: Vector3 | null;
|
|
@@ -324,7 +333,7 @@ export default class Tileset3D {
|
|
|
324
333
|
this.credits = {};
|
|
325
334
|
this.description = this.options.description || '';
|
|
326
335
|
|
|
327
|
-
this._initializeTileSet(json);
|
|
336
|
+
this.tilesetInitializationPromise = this._initializeTileSet(json);
|
|
328
337
|
}
|
|
329
338
|
|
|
330
339
|
/** Release resources */
|
|
@@ -382,20 +391,55 @@ export default class Tileset3D {
|
|
|
382
391
|
/**
|
|
383
392
|
* Update visible tiles relying on a list of viewports
|
|
384
393
|
* @param viewports - list of viewports
|
|
394
|
+
* @deprecated
|
|
395
|
+
*/
|
|
396
|
+
update(viewports: any[] | null = null) {
|
|
397
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
398
|
+
this.tilesetInitializationPromise.then(() => {
|
|
399
|
+
if (!viewports && this.lastUpdatedVieports) {
|
|
400
|
+
viewports = this.lastUpdatedVieports;
|
|
401
|
+
} else {
|
|
402
|
+
this.lastUpdatedVieports = viewports;
|
|
403
|
+
}
|
|
404
|
+
this.doUpdate(viewports);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Update visible tiles relying on a list of viewports.
|
|
410
|
+
* Do it with debounce delay to prevent update spam
|
|
411
|
+
* @param viewports viewports
|
|
412
|
+
* @returns Promise of new frameNumber
|
|
413
|
+
*/
|
|
414
|
+
async selectTiles(viewports: any[] | null = null): Promise<number> {
|
|
415
|
+
await this.tilesetInitializationPromise;
|
|
416
|
+
if (viewports) {
|
|
417
|
+
this.lastUpdatedVieports = viewports;
|
|
418
|
+
}
|
|
419
|
+
if (!this.updatePromise) {
|
|
420
|
+
this.updatePromise = new Promise<number>((resolve) => {
|
|
421
|
+
setTimeout(() => {
|
|
422
|
+
this.doUpdate(this.lastUpdatedVieports);
|
|
423
|
+
resolve(this._frameNumber);
|
|
424
|
+
this.updatePromise = null;
|
|
425
|
+
}, this.options.debounceTime);
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
return this.updatePromise;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Update visible tiles relying on a list of viewports
|
|
433
|
+
* @param viewports viewports
|
|
385
434
|
*/
|
|
386
435
|
// eslint-disable-next-line max-statements, complexity
|
|
387
|
-
|
|
436
|
+
private doUpdate(viewports: any[] | null = null): void {
|
|
388
437
|
if ('loadTiles' in this.options && !this.options.loadTiles) {
|
|
389
438
|
return;
|
|
390
439
|
}
|
|
391
440
|
if (this.traverseCounter > 0) {
|
|
392
441
|
return;
|
|
393
442
|
}
|
|
394
|
-
if (!viewports && this.lastUpdatedVieports) {
|
|
395
|
-
viewports = this.lastUpdatedVieports;
|
|
396
|
-
} else {
|
|
397
|
-
this.lastUpdatedVieports = viewports;
|
|
398
|
-
}
|
|
399
443
|
if (!(viewports instanceof Array)) {
|
|
400
444
|
viewports = [viewports];
|
|
401
445
|
}
|
|
@@ -457,7 +501,16 @@ export default class Tileset3D {
|
|
|
457
501
|
}
|
|
458
502
|
const currentFrameStateData = this.frameStateData[id];
|
|
459
503
|
const selectedTiles = Object.values(this._traverser.selectedTiles);
|
|
460
|
-
|
|
504
|
+
const [filteredSelectedTiles, unselectedTiles] = limitSelectedTiles(
|
|
505
|
+
selectedTiles,
|
|
506
|
+
frameState,
|
|
507
|
+
this.options.maximumTilesSelected
|
|
508
|
+
);
|
|
509
|
+
currentFrameStateData.selectedTiles = filteredSelectedTiles;
|
|
510
|
+
for (const tile of unselectedTiles) {
|
|
511
|
+
tile.unselect();
|
|
512
|
+
}
|
|
513
|
+
|
|
461
514
|
currentFrameStateData._requestedTiles = Object.values(this._traverser.requestedTiles);
|
|
462
515
|
currentFrameStateData._emptyTiles = Object.values(this._traverser.emptyTiles);
|
|
463
516
|
|
|
@@ -540,29 +593,78 @@ export default class Tileset3D {
|
|
|
540
593
|
this.stats.get(POINTS_COUNT).count = pointsRenderable;
|
|
541
594
|
}
|
|
542
595
|
|
|
543
|
-
_initializeTileSet(tilesetJson) {
|
|
596
|
+
async _initializeTileSet(tilesetJson) {
|
|
597
|
+
if (this.type === TILESET_TYPE.I3S) {
|
|
598
|
+
this.calculateViewPropsI3S();
|
|
599
|
+
tilesetJson.root = await tilesetJson.root;
|
|
600
|
+
}
|
|
544
601
|
this.root = this._initializeTileHeaders(tilesetJson, null);
|
|
545
602
|
|
|
546
|
-
// TODO CESIUM Specific
|
|
547
603
|
if (this.type === TILESET_TYPE.TILES3D) {
|
|
548
|
-
this.
|
|
604
|
+
this._initializeTiles3DTileset(tilesetJson);
|
|
605
|
+
this.calculateViewPropsTiles3D();
|
|
549
606
|
}
|
|
550
607
|
|
|
551
608
|
if (this.type === TILESET_TYPE.I3S) {
|
|
552
609
|
this._initializeI3STileset();
|
|
553
610
|
}
|
|
554
|
-
// Calculate cartographicCenter & zoom props to help apps center view on tileset
|
|
555
|
-
this._calculateViewProps();
|
|
556
611
|
}
|
|
557
612
|
|
|
558
|
-
|
|
559
|
-
|
|
613
|
+
/**
|
|
614
|
+
* Called during initialize Tileset to initialize the tileset's cartographic center (longitude, latitude) and zoom.
|
|
615
|
+
* These metrics help apps center view on tileset
|
|
616
|
+
* For I3S there is extent (<1.8 version) or fullExtent (>=1.8 version) to calculate view props
|
|
617
|
+
* @returns
|
|
618
|
+
*/
|
|
619
|
+
private calculateViewPropsI3S() {
|
|
620
|
+
// for I3S 1.8 try to calculate with fullExtent
|
|
621
|
+
const fullExtent = this.tileset.fullExtent;
|
|
622
|
+
if (fullExtent) {
|
|
623
|
+
const {xmin, xmax, ymin, ymax, zmin, zmax} = fullExtent;
|
|
624
|
+
this.cartographicCenter = new Vector3(
|
|
625
|
+
xmin + (xmax - xmin) / 2,
|
|
626
|
+
ymin + (ymax - ymin) / 2,
|
|
627
|
+
zmin + (zmax - zmin) / 2
|
|
628
|
+
);
|
|
629
|
+
this.cartesianCenter = Ellipsoid.WGS84.cartographicToCartesian(
|
|
630
|
+
this.cartographicCenter,
|
|
631
|
+
new Vector3()
|
|
632
|
+
);
|
|
633
|
+
this.zoom = getZoomFromFullExtent(fullExtent, this.cartographicCenter, this.cartesianCenter);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
// for I3S 1.6-1.7 try to calculate with extent
|
|
637
|
+
const extent = this.tileset.store?.extent;
|
|
638
|
+
if (extent) {
|
|
639
|
+
const [xmin, ymin, xmax, ymax] = extent;
|
|
640
|
+
this.cartographicCenter = new Vector3(xmin + (xmax - xmin) / 2, ymin + (ymax - ymin) / 2, 0);
|
|
641
|
+
this.cartesianCenter = Ellipsoid.WGS84.cartographicToCartesian(
|
|
642
|
+
this.cartographicCenter,
|
|
643
|
+
new Vector3()
|
|
644
|
+
);
|
|
645
|
+
this.zoom = getZoomFromExtent(extent, this.cartographicCenter, this.cartesianCenter);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
// eslint-disable-next-line no-console
|
|
649
|
+
console.warn('Extent is not defined in the tileset header');
|
|
650
|
+
this.cartographicCenter = new Vector3();
|
|
651
|
+
this.zoom = 1;
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Called during initialize Tileset to initialize the tileset's cartographic center (longitude, latitude) and zoom.
|
|
657
|
+
* These metrics help apps center view on tileset.
|
|
658
|
+
* For 3DTiles the root tile data is used to calculate view props.
|
|
659
|
+
* @returns
|
|
660
|
+
*/
|
|
661
|
+
private calculateViewPropsTiles3D() {
|
|
560
662
|
const root = this.root as Tile3D;
|
|
561
663
|
assert(root);
|
|
562
664
|
const {center} = root.boundingVolume;
|
|
563
665
|
// TODO - handle all cases
|
|
564
666
|
if (!center) {
|
|
565
|
-
// eslint-disable-next-line
|
|
667
|
+
// eslint-disable-next-line no-console
|
|
566
668
|
console.warn('center was not pre-calculated for the root tile');
|
|
567
669
|
this.cartographicCenter = new Vector3();
|
|
568
670
|
this.zoom = 1;
|
|
@@ -600,7 +702,7 @@ export default class Tileset3D {
|
|
|
600
702
|
rootTile.depth = parentTileHeader.depth + 1;
|
|
601
703
|
}
|
|
602
704
|
|
|
603
|
-
//
|
|
705
|
+
// 3DTiles knows the hierarchy beforehand
|
|
604
706
|
if (this.type === TILESET_TYPE.TILES3D) {
|
|
605
707
|
const stack: Tile3D[] = [];
|
|
606
708
|
stack.push(rootTile);
|
|
@@ -759,7 +861,7 @@ export default class Tileset3D {
|
|
|
759
861
|
tile.destroy();
|
|
760
862
|
}
|
|
761
863
|
|
|
762
|
-
|
|
864
|
+
_initializeTiles3DTileset(tilesetJson) {
|
|
763
865
|
this.asset = tilesetJson.asset;
|
|
764
866
|
if (!this.asset) {
|
|
765
867
|
throw new Error('Tileset must have an asset property.');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter to register pending tile headers for the particular frameNumber
|
|
3
|
+
* Until all tiles are loaded we won't call `onTraversalEnd` callback
|
|
4
|
+
*/
|
|
5
|
+
export default class I3SPendingTilesRegister {
|
|
6
|
+
private frameNumberMap: Map<number, number> = new Map();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register a new pending tile header for the particular frameNumber
|
|
10
|
+
* @param frameNumber
|
|
11
|
+
*/
|
|
12
|
+
register(frameNumber: number) {
|
|
13
|
+
const oldCount = this.frameNumberMap.get(frameNumber) || 0;
|
|
14
|
+
this.frameNumberMap.set(frameNumber, (oldCount || 0) + 1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Deregister a pending tile header for the particular frameNumber
|
|
19
|
+
* @param frameNumber
|
|
20
|
+
*/
|
|
21
|
+
deregister(frameNumber: number) {
|
|
22
|
+
const oldCount = this.frameNumberMap.get(frameNumber) || 1;
|
|
23
|
+
this.frameNumberMap.set(frameNumber, (oldCount || 0) - 1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check is there are no pending tile headers registered for the particular frameNumber
|
|
28
|
+
* @param frameNumber
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
isZero(frameNumber: number) {
|
|
32
|
+
const count = this.frameNumberMap.get(frameNumber) || 0;
|
|
33
|
+
return count === 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {FrameState} from '../helpers/frame-state';
|
|
2
|
+
import I3SPendingTilesRegister from './i3s-frame-counter';
|
|
3
|
+
|
|
1
4
|
const STATUS = {
|
|
2
5
|
REQUESTED: 'REQUESTED',
|
|
3
6
|
COMPLETED: 'COMPLETED',
|
|
@@ -7,28 +10,40 @@ const STATUS = {
|
|
|
7
10
|
// A helper class to manage tile metadata fetching
|
|
8
11
|
export default class I3STileManager {
|
|
9
12
|
private _statusMap: object;
|
|
13
|
+
private pendingTilesRegister = new I3SPendingTilesRegister();
|
|
10
14
|
|
|
11
15
|
constructor() {
|
|
12
16
|
this._statusMap = {};
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
add(request, key, callback, frameState) {
|
|
19
|
+
add(request, key, callback, frameState: FrameState) {
|
|
16
20
|
if (!this._statusMap[key]) {
|
|
21
|
+
const {frameNumber} = frameState;
|
|
17
22
|
this._statusMap[key] = {request, callback, key, frameState, status: STATUS.REQUESTED};
|
|
23
|
+
// Register pending request for the frameNumber
|
|
24
|
+
this.pendingTilesRegister.register(frameNumber);
|
|
18
25
|
request()
|
|
19
26
|
.then((data) => {
|
|
20
27
|
this._statusMap[key].status = STATUS.COMPLETED;
|
|
28
|
+
// Deregister pending request for the frameNumber
|
|
29
|
+
this.pendingTilesRegister.deregister(frameNumber);
|
|
21
30
|
this._statusMap[key].callback(data, frameState);
|
|
22
31
|
})
|
|
23
32
|
.catch((error) => {
|
|
24
33
|
this._statusMap[key].status = STATUS.ERROR;
|
|
34
|
+
// Deregister pending request for the frameNumber
|
|
35
|
+
this.pendingTilesRegister.deregister(frameNumber);
|
|
25
36
|
callback(error);
|
|
26
37
|
});
|
|
27
38
|
}
|
|
28
39
|
}
|
|
29
40
|
|
|
30
|
-
update(key, frameState) {
|
|
41
|
+
update(key, frameState: FrameState) {
|
|
31
42
|
if (this._statusMap[key]) {
|
|
43
|
+
// Deregister pending request for the old frameNumber
|
|
44
|
+
this.pendingTilesRegister.deregister(this._statusMap[key].frameState.frameNumber);
|
|
45
|
+
// Register pending request for the new frameNumber
|
|
46
|
+
this.pendingTilesRegister.register(frameState.frameNumber);
|
|
32
47
|
this._statusMap[key].frameState = frameState;
|
|
33
48
|
}
|
|
34
49
|
}
|
|
@@ -36,4 +51,13 @@ export default class I3STileManager {
|
|
|
36
51
|
find(key) {
|
|
37
52
|
return this._statusMap[key];
|
|
38
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check it there are pending tile headers for the particular frameNumber
|
|
57
|
+
* @param frameNumber
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
hasPendingTiles(frameNumber: number): boolean {
|
|
61
|
+
return !this.pendingTilesRegister.isZero(frameNumber);
|
|
62
|
+
}
|
|
39
63
|
}
|
|
@@ -4,21 +4,31 @@ import TilesetTraverser from './tileset-traverser';
|
|
|
4
4
|
import {getLodStatus} from '../helpers/i3s-lod';
|
|
5
5
|
import TileHeader from '../tile-3d';
|
|
6
6
|
import I3STileManager from './i3s-tile-manager';
|
|
7
|
+
import {FrameState} from '../helpers/frame-state';
|
|
7
8
|
|
|
8
9
|
export default class I3STilesetTraverser extends TilesetTraverser {
|
|
9
10
|
private _tileManager: I3STileManager;
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Check if there are no penging tile header requests,
|
|
14
|
+
* that means the traversal is finished and we can call
|
|
15
|
+
* following-up callbacks.
|
|
16
|
+
*/
|
|
17
|
+
protected get traversalFinished(): boolean {
|
|
18
|
+
return !this._tileManager.hasPendingTiles(this._frameNumber || 0);
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
constructor(options) {
|
|
12
22
|
super(options);
|
|
13
23
|
this._tileManager = new I3STileManager();
|
|
14
24
|
}
|
|
15
25
|
|
|
16
|
-
shouldRefine(tile, frameState) {
|
|
26
|
+
shouldRefine(tile, frameState: FrameState) {
|
|
17
27
|
tile._lodJudge = getLodStatus(tile, frameState);
|
|
18
28
|
return tile._lodJudge === 'DIG';
|
|
19
29
|
}
|
|
20
30
|
|
|
21
|
-
updateChildTiles(tile, frameState): boolean {
|
|
31
|
+
updateChildTiles(tile, frameState: FrameState): boolean {
|
|
22
32
|
const children = tile.header.children || [];
|
|
23
33
|
// children which are already fetched and constructed as Tile3D instances
|
|
24
34
|
const childTiles = tile.children;
|
|
@@ -86,7 +96,10 @@ export default class I3STilesetTraverser extends TilesetTraverser {
|
|
|
86
96
|
this.updateTile(childTile, frameState);
|
|
87
97
|
|
|
88
98
|
// after tile fetched, resume traversal if still in current update/traversal frame
|
|
89
|
-
if (
|
|
99
|
+
if (
|
|
100
|
+
this._frameNumber === frameState.frameNumber &&
|
|
101
|
+
(this.traversalFinished || new Date().getTime() - this.lastUpdate > this.updateDebounceTime)
|
|
102
|
+
) {
|
|
90
103
|
this.executeTraversal(childTile, frameState);
|
|
91
104
|
}
|
|
92
105
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ManagedArray from '../../utils/managed-array';
|
|
2
2
|
import {TILE_REFINEMENT} from '../../constants';
|
|
3
|
+
import {FrameState} from '../helpers/frame-state';
|
|
3
4
|
|
|
4
5
|
export type TilesetTraverserProps = {
|
|
5
6
|
loadSiblings?: boolean;
|
|
@@ -38,10 +39,16 @@ export default class TilesetTraverser {
|
|
|
38
39
|
selectedTiles: object;
|
|
39
40
|
emptyTiles: object;
|
|
40
41
|
|
|
42
|
+
protected lastUpdate: number = new Date().getTime();
|
|
43
|
+
protected readonly updateDebounceTime = 1000;
|
|
41
44
|
protected _traversalStack: ManagedArray;
|
|
42
45
|
protected _emptyTraversalStack: ManagedArray;
|
|
43
46
|
protected _frameNumber: number | null;
|
|
44
47
|
|
|
48
|
+
protected get traversalFinished(): boolean {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
// TODO nested props
|
|
46
53
|
constructor(options: TilesetTraverserProps) {
|
|
47
54
|
this.options = {...DEFAULT_PROPS, ...options};
|
|
@@ -96,7 +103,7 @@ export default class TilesetTraverser {
|
|
|
96
103
|
// all other tiles are part of the skip traversal. The skip traversal allows for skipping levels of the tree
|
|
97
104
|
// and rendering children and parent tiles simultaneously.
|
|
98
105
|
/* eslint-disable-next-line complexity, max-statements */
|
|
99
|
-
executeTraversal(root, frameState) {
|
|
106
|
+
executeTraversal(root, frameState: FrameState) {
|
|
100
107
|
// stack to store traversed tiles, only visible tiles should be added to stack
|
|
101
108
|
// visible: visible in the current view frustum
|
|
102
109
|
const stack = this._traversalStack;
|
|
@@ -156,7 +163,11 @@ export default class TilesetTraverser {
|
|
|
156
163
|
tile._shouldRefine = shouldRefine && parentRefines;
|
|
157
164
|
}
|
|
158
165
|
|
|
159
|
-
|
|
166
|
+
const newTime = new Date().getTime();
|
|
167
|
+
if (this.traversalFinished || newTime - this.lastUpdate > this.updateDebounceTime) {
|
|
168
|
+
this.lastUpdate = newTime;
|
|
169
|
+
this.options.onTraversalEnd(frameState);
|
|
170
|
+
}
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
updateChildTiles(tile, frameState) {
|