@loaders.gl/tiles 4.0.0-alpha.4 → 4.0.0-alpha.6
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/bundle.d.ts +2 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +2 -2
- package/dist/constants.d.ts +32 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +30 -26
- package/dist/dist.min.js +8921 -0
- package/dist/es5/bundle.js +6 -0
- package/dist/es5/bundle.js.map +1 -0
- package/dist/es5/constants.js +44 -0
- package/dist/es5/constants.js.map +1 -0
- package/dist/es5/index.js +93 -0
- package/dist/es5/index.js.map +1 -0
- package/dist/es5/tileset/format-3d-tiles/tileset-3d-traverser.js +70 -0
- package/dist/es5/tileset/format-3d-tiles/tileset-3d-traverser.js.map +1 -0
- package/dist/es5/tileset/format-i3s/i3s-pending-tiles-register.js +45 -0
- package/dist/es5/tileset/format-i3s/i3s-pending-tiles-register.js.map +1 -0
- package/dist/es5/tileset/format-i3s/i3s-tile-manager.js +84 -0
- package/dist/es5/tileset/format-i3s/i3s-tile-manager.js.map +1 -0
- package/dist/es5/tileset/format-i3s/i3s-tileset-traverser.js +143 -0
- package/dist/es5/tileset/format-i3s/i3s-tileset-traverser.js.map +1 -0
- package/dist/es5/tileset/helpers/3d-tiles-options.js +12 -0
- package/dist/es5/tileset/helpers/3d-tiles-options.js.map +1 -0
- package/dist/es5/tileset/helpers/bounding-volume.js +176 -0
- package/dist/es5/tileset/helpers/bounding-volume.js.map +1 -0
- package/dist/es5/tileset/helpers/frame-state.js +129 -0
- package/dist/es5/tileset/helpers/frame-state.js.map +1 -0
- package/dist/es5/tileset/helpers/i3s-lod.js +60 -0
- package/dist/es5/tileset/helpers/i3s-lod.js.map +1 -0
- package/dist/es5/tileset/helpers/tiles-3d-lod.js +103 -0
- package/dist/es5/tileset/helpers/tiles-3d-lod.js.map +1 -0
- package/dist/es5/tileset/helpers/transform-utils.js +50 -0
- package/dist/es5/tileset/helpers/transform-utils.js.map +1 -0
- package/dist/es5/tileset/helpers/zoom.js +63 -0
- package/dist/es5/tileset/helpers/zoom.js.map +1 -0
- package/dist/es5/tileset/tile-3d.js +565 -0
- package/dist/es5/tileset/tile-3d.js.map +1 -0
- package/dist/es5/tileset/tileset-3d.js +890 -0
- package/dist/es5/tileset/tileset-3d.js.map +1 -0
- package/dist/es5/tileset/tileset-cache.js +85 -0
- package/dist/es5/tileset/tileset-cache.js.map +1 -0
- package/dist/es5/tileset/tileset-traverser.js +328 -0
- package/dist/es5/tileset/tileset-traverser.js.map +1 -0
- package/dist/es5/types.js +2 -0
- package/dist/es5/types.js.map +1 -0
- package/dist/es5/utils/doubly-linked-list-node.js +21 -0
- package/dist/es5/utils/doubly-linked-list-node.js.map +1 -0
- package/dist/es5/utils/doubly-linked-list.js +88 -0
- package/dist/es5/utils/doubly-linked-list.js.map +1 -0
- package/dist/es5/utils/managed-array.js +126 -0
- package/dist/es5/utils/managed-array.js.map +1 -0
- package/dist/esm/bundle.js +4 -0
- package/dist/esm/bundle.js.map +1 -0
- package/dist/esm/constants.js +32 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/{tileset/traversers → esm/tileset/format-3d-tiles}/tileset-3d-traverser.js +2 -13
- package/dist/esm/tileset/format-3d-tiles/tileset-3d-traverser.js.map +1 -0
- package/dist/esm/tileset/format-i3s/i3s-pending-tiles-register.js +26 -0
- package/dist/esm/tileset/format-i3s/i3s-pending-tiles-register.js.map +1 -0
- package/dist/esm/tileset/format-i3s/i3s-tile-manager.js +79 -0
- package/dist/esm/tileset/format-i3s/i3s-tile-manager.js.map +1 -0
- package/dist/{tileset/traversers → esm/tileset/format-i3s}/i3s-tileset-traverser.js +16 -28
- package/dist/esm/tileset/format-i3s/i3s-tileset-traverser.js.map +1 -0
- package/dist/esm/tileset/helpers/3d-tiles-options.js +6 -0
- package/dist/esm/tileset/helpers/3d-tiles-options.js.map +1 -0
- package/dist/esm/tileset/helpers/bounding-volume.js +155 -0
- package/dist/esm/tileset/helpers/bounding-volume.js.map +1 -0
- package/dist/esm/tileset/helpers/frame-state.js +109 -0
- package/dist/esm/tileset/helpers/frame-state.js.map +1 -0
- package/dist/esm/tileset/helpers/i3s-lod.js +53 -0
- package/dist/esm/tileset/helpers/i3s-lod.js.map +1 -0
- package/dist/esm/tileset/helpers/tiles-3d-lod.js +100 -0
- package/dist/{tileset → esm/tileset}/helpers/tiles-3d-lod.js.map +1 -1
- package/dist/esm/tileset/helpers/transform-utils.js +50 -0
- package/dist/esm/tileset/helpers/transform-utils.js.map +1 -0
- package/dist/esm/tileset/helpers/zoom.js +55 -0
- package/dist/esm/tileset/helpers/zoom.js.map +1 -0
- package/dist/esm/tileset/tile-3d.js +445 -0
- package/dist/esm/tileset/tile-3d.js.map +1 -0
- package/dist/esm/tileset/tileset-3d.js +637 -0
- package/dist/esm/tileset/tileset-3d.js.map +1 -0
- package/dist/esm/tileset/tileset-cache.js +60 -0
- package/dist/esm/tileset/tileset-cache.js.map +1 -0
- package/dist/{tileset/traversers → esm/tileset}/tileset-traverser.js +20 -72
- package/dist/esm/tileset/tileset-traverser.js.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils/doubly-linked-list-node.js +12 -0
- package/dist/esm/utils/doubly-linked-list-node.js.map +1 -0
- package/dist/esm/utils/doubly-linked-list.js +65 -0
- package/dist/esm/utils/doubly-linked-list.js.map +1 -0
- package/dist/esm/utils/managed-array.js +87 -0
- package/dist/esm/utils/managed-array.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -9
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts +7 -0
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -0
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js +54 -0
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.d.ts +27 -0
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.d.ts.map +1 -0
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.js +47 -0
- package/dist/tileset/format-i3s/i3s-tile-manager.d.ts +34 -0
- package/dist/tileset/format-i3s/i3s-tile-manager.d.ts.map +1 -0
- package/dist/tileset/format-i3s/i3s-tile-manager.js +80 -0
- package/dist/tileset/format-i3s/i3s-tileset-traverser.d.ts +25 -0
- package/dist/tileset/format-i3s/i3s-tileset-traverser.d.ts.map +1 -0
- package/dist/tileset/format-i3s/i3s-tileset-traverser.js +92 -0
- package/dist/tileset/helpers/3d-tiles-options.d.ts +4 -0
- package/dist/tileset/helpers/3d-tiles-options.d.ts.map +1 -0
- package/dist/tileset/helpers/3d-tiles-options.js +8 -5
- package/dist/tileset/helpers/bounding-volume.d.ts +19 -0
- package/dist/tileset/helpers/bounding-volume.d.ts.map +1 -0
- package/dist/tileset/helpers/bounding-volume.js +274 -69
- package/dist/tileset/helpers/frame-state.d.ts +28 -0
- package/dist/tileset/helpers/frame-state.d.ts.map +1 -0
- package/dist/tileset/helpers/frame-state.js +131 -49
- package/dist/tileset/helpers/i3s-lod.d.ts +20 -0
- package/dist/tileset/helpers/i3s-lod.d.ts.map +1 -0
- package/dist/tileset/helpers/i3s-lod.js +82 -105
- package/dist/tileset/helpers/tiles-3d-lod.d.ts +8 -0
- package/dist/tileset/helpers/tiles-3d-lod.d.ts.map +1 -0
- package/dist/tileset/helpers/tiles-3d-lod.js +112 -100
- package/dist/tileset/helpers/transform-utils.d.ts +2 -0
- package/dist/tileset/helpers/transform-utils.d.ts.map +1 -0
- package/dist/tileset/helpers/transform-utils.js +51 -56
- package/dist/tileset/helpers/zoom.d.ts +46 -0
- package/dist/tileset/helpers/zoom.d.ts.map +1 -0
- package/dist/tileset/helpers/zoom.js +83 -30
- package/dist/tileset/tile-3d.d.ts +206 -0
- package/dist/tileset/tile-3d.d.ts.map +1 -0
- package/dist/tileset/tile-3d.js +593 -531
- package/dist/tileset/tileset-3d.d.ts +217 -0
- package/dist/tileset/tileset-3d.d.ts.map +1 -0
- package/dist/tileset/tileset-3d.js +707 -648
- package/dist/tileset/tileset-cache.d.ts +18 -0
- package/dist/tileset/tileset-cache.d.ts.map +1 -0
- package/dist/tileset/tileset-cache.js +70 -71
- package/dist/tileset/tileset-traverser.d.ts +46 -0
- package/dist/tileset/tileset-traverser.d.ts.map +1 -0
- package/dist/tileset/tileset-traverser.js +309 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/utils/doubly-linked-list-node.d.ts +11 -0
- package/dist/utils/doubly-linked-list-node.d.ts.map +1 -0
- package/dist/utils/doubly-linked-list-node.js +17 -8
- package/dist/utils/doubly-linked-list.d.ts +30 -0
- package/dist/utils/doubly-linked-list.d.ts.map +1 -0
- package/dist/utils/doubly-linked-list.js +91 -72
- package/dist/utils/managed-array.d.ts +85 -0
- package/dist/utils/managed-array.d.ts.map +1 -0
- package/dist/utils/managed-array.js +144 -103
- package/package.json +10 -10
- package/src/constants.ts +2 -0
- package/src/index.ts +7 -4
- package/src/tileset/{traversers → format-3d-tiles}/tileset-3d-traverser.ts +4 -2
- package/src/tileset/format-i3s/i3s-pending-tiles-register.ts +44 -0
- package/src/tileset/format-i3s/i3s-tile-manager.ts +101 -0
- package/src/tileset/{traversers → format-i3s}/i3s-tileset-traverser.ts +27 -15
- package/src/tileset/helpers/bounding-volume.ts +136 -0
- package/src/tileset/helpers/frame-state.ts +102 -18
- package/src/tileset/helpers/i3s-lod.ts +75 -96
- package/src/tileset/helpers/tiles-3d-lod.ts +2 -0
- package/src/tileset/helpers/transform-utils.ts +2 -0
- package/src/tileset/helpers/zoom.ts +84 -9
- package/src/tileset/tile-3d.ts +77 -20
- package/src/tileset/tileset-3d.ts +205 -43
- package/src/tileset/tileset-cache.ts +6 -2
- package/src/tileset/{traversers/tileset-traverser.ts → tileset-traverser.ts} +29 -17
- package/src/types.ts +36 -0
- package/src/utils/{doubly-linked-list-node.js → doubly-linked-list-node.ts} +7 -2
- package/src/utils/{doubly-linked-list.js → doubly-linked-list.ts} +5 -8
- package/src/utils/{managed-array.js → managed-array.ts} +5 -2
- package/dist/bundle.js.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/tileset/helpers/3d-tiles-options.js.map +0 -1
- package/dist/tileset/helpers/bounding-volume.js.map +0 -1
- package/dist/tileset/helpers/frame-state.js.map +0 -1
- package/dist/tileset/helpers/i3s-lod.js.map +0 -1
- package/dist/tileset/helpers/transform-utils.js.map +0 -1
- package/dist/tileset/helpers/zoom.js.map +0 -1
- package/dist/tileset/tile-3d.js.map +0 -1
- package/dist/tileset/tileset-3d.js.map +0 -1
- package/dist/tileset/tileset-cache.js.map +0 -1
- package/dist/tileset/traversers/i3s-tile-manager.js +0 -45
- package/dist/tileset/traversers/i3s-tile-manager.js.map +0 -1
- package/dist/tileset/traversers/i3s-tileset-traverser.js.map +0 -1
- package/dist/tileset/traversers/tileset-3d-traverser.js.map +0 -1
- package/dist/tileset/traversers/tileset-traverser.js.map +0 -1
- package/dist/utils/doubly-linked-list-node.js.map +0 -1
- package/dist/utils/doubly-linked-list.js.map +0 -1
- package/dist/utils/managed-array.js.map +0 -1
- package/src/tileset/traversers/i3s-tile-manager.ts +0 -39
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {FrameState} from '../helpers/frame-state';
|
|
2
|
+
import {I3SPendingTilesRegister} from './i3s-pending-tiles-register';
|
|
3
|
+
|
|
4
|
+
const STATUS = {
|
|
5
|
+
REQUESTED: 'REQUESTED',
|
|
6
|
+
COMPLETED: 'COMPLETED',
|
|
7
|
+
ERROR: 'ERROR'
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// A helper class to manage tile metadata fetching
|
|
11
|
+
export class I3STileManager {
|
|
12
|
+
private _statusMap: object;
|
|
13
|
+
private pendingTilesRegister = new I3SPendingTilesRegister();
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
this._statusMap = {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Add request to map
|
|
21
|
+
* @param request - node metadata request
|
|
22
|
+
* @param key - unique key
|
|
23
|
+
* @param callback - callback after request completed
|
|
24
|
+
* @param frameState - frameState data
|
|
25
|
+
*/
|
|
26
|
+
add(request, key, callback, frameState: FrameState) {
|
|
27
|
+
if (!this._statusMap[key]) {
|
|
28
|
+
const {
|
|
29
|
+
frameNumber,
|
|
30
|
+
viewport: {id}
|
|
31
|
+
} = frameState;
|
|
32
|
+
this._statusMap[key] = {request, callback, key, frameState, status: STATUS.REQUESTED};
|
|
33
|
+
// Register pending request for the frameNumber
|
|
34
|
+
this.pendingTilesRegister.register(id, frameNumber);
|
|
35
|
+
request()
|
|
36
|
+
.then((data) => {
|
|
37
|
+
this._statusMap[key].status = STATUS.COMPLETED;
|
|
38
|
+
const {
|
|
39
|
+
frameNumber: actualFrameNumber,
|
|
40
|
+
viewport: {id}
|
|
41
|
+
} = this._statusMap[key].frameState;
|
|
42
|
+
// Deregister pending request for the frameNumber
|
|
43
|
+
this.pendingTilesRegister.deregister(id, actualFrameNumber);
|
|
44
|
+
this._statusMap[key].callback(data, frameState);
|
|
45
|
+
})
|
|
46
|
+
.catch((error) => {
|
|
47
|
+
this._statusMap[key].status = STATUS.ERROR;
|
|
48
|
+
const {
|
|
49
|
+
frameNumber: actualFrameNumber,
|
|
50
|
+
viewport: {id}
|
|
51
|
+
} = this._statusMap[key].frameState;
|
|
52
|
+
// Deregister pending request for the frameNumber
|
|
53
|
+
this.pendingTilesRegister.deregister(id, actualFrameNumber);
|
|
54
|
+
callback(error);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Update request if it is still actual for the new frameState
|
|
61
|
+
* @param key - unique key
|
|
62
|
+
* @param frameState - frameState data
|
|
63
|
+
*/
|
|
64
|
+
update(key, frameState: FrameState) {
|
|
65
|
+
if (this._statusMap[key]) {
|
|
66
|
+
// Deregister pending request for the old frameNumber
|
|
67
|
+
const {
|
|
68
|
+
frameNumber,
|
|
69
|
+
viewport: {id}
|
|
70
|
+
} = this._statusMap[key].frameState;
|
|
71
|
+
this.pendingTilesRegister.deregister(id, frameNumber);
|
|
72
|
+
|
|
73
|
+
// Register pending request for the new frameNumber
|
|
74
|
+
const {
|
|
75
|
+
frameNumber: newFrameNumber,
|
|
76
|
+
viewport: {id: newViewportId}
|
|
77
|
+
} = frameState;
|
|
78
|
+
this.pendingTilesRegister.register(newViewportId, newFrameNumber);
|
|
79
|
+
this._statusMap[key].frameState = frameState;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Find request in the map
|
|
85
|
+
* @param key - unique key
|
|
86
|
+
* @returns
|
|
87
|
+
*/
|
|
88
|
+
find(key) {
|
|
89
|
+
return this._statusMap[key];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Check it there are pending tile headers for the particular frameNumber
|
|
94
|
+
* @param viewportId
|
|
95
|
+
* @param frameNumber
|
|
96
|
+
* @returns
|
|
97
|
+
*/
|
|
98
|
+
hasPendingTiles(viewportId: string, frameNumber: number): boolean {
|
|
99
|
+
return !this.pendingTilesRegister.isZero(viewportId, frameNumber);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {load} from '@loaders.gl/core';
|
|
2
|
-
import TilesetTraverser from '
|
|
2
|
+
import {TilesetTraverser} from '../tileset-traverser';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import I3STileManager from './i3s-tile-manager';
|
|
4
|
+
import {getLodStatus} from '../helpers/i3s-lod';
|
|
5
|
+
import {Tile3D} from '../tile-3d';
|
|
6
|
+
import {I3STileManager} from './i3s-tile-manager';
|
|
7
|
+
import {FrameState} from '../helpers/frame-state';
|
|
7
8
|
|
|
8
|
-
export
|
|
9
|
+
export class I3STilesetTraverser extends TilesetTraverser {
|
|
9
10
|
private _tileManager: I3STileManager;
|
|
10
11
|
|
|
11
12
|
constructor(options) {
|
|
@@ -13,13 +14,21 @@ export default class I3STilesetTraverser extends TilesetTraverser {
|
|
|
13
14
|
this._tileManager = new I3STileManager();
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Check if there are no penging tile header requests,
|
|
19
|
+
* that means the traversal is finished and we can call
|
|
20
|
+
* following-up callbacks.
|
|
21
|
+
*/
|
|
22
|
+
traversalFinished(frameState: FrameState): boolean {
|
|
23
|
+
return !this._tileManager.hasPendingTiles(frameState.viewport.id, this._frameNumber || 0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
shouldRefine(tile, frameState: FrameState) {
|
|
27
|
+
tile._lodJudge = getLodStatus(tile, frameState);
|
|
19
28
|
return tile._lodJudge === 'DIG';
|
|
20
29
|
}
|
|
21
30
|
|
|
22
|
-
updateChildTiles(tile, frameState): boolean {
|
|
31
|
+
updateChildTiles(tile, frameState: FrameState): boolean {
|
|
23
32
|
const children = tile.header.children || [];
|
|
24
33
|
// children which are already fetched and constructed as Tile3D instances
|
|
25
34
|
const childTiles = tile.children;
|
|
@@ -63,8 +72,7 @@ export default class I3STilesetTraverser extends TilesetTraverser {
|
|
|
63
72
|
...tileset.loadOptions,
|
|
64
73
|
i3s: {
|
|
65
74
|
...tileset.loadOptions.i3s,
|
|
66
|
-
isTileHeader: true
|
|
67
|
-
loadContent: false
|
|
75
|
+
isTileHeader: true
|
|
68
76
|
}
|
|
69
77
|
};
|
|
70
78
|
|
|
@@ -72,22 +80,26 @@ export default class I3STilesetTraverser extends TilesetTraverser {
|
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
/**
|
|
75
|
-
* The callback to init
|
|
83
|
+
* The callback to init Tile3D instance after loading the tile JSON
|
|
76
84
|
* @param {Object} header - the tile JSON from a dataset
|
|
77
|
-
* @param {
|
|
85
|
+
* @param {Tile3D} tile - the parent Tile3D instance
|
|
78
86
|
* @param {string} extendedId - optional ID to separate copies of a tile for different viewports.
|
|
79
87
|
* const extendedId = `${tile.id}-${frameState.viewport.id}`;
|
|
80
88
|
* @return {void}
|
|
81
89
|
*/
|
|
82
90
|
_onTileLoad(header, tile, extendedId) {
|
|
83
91
|
// after child tile is fetched
|
|
84
|
-
const childTile = new
|
|
92
|
+
const childTile = new Tile3D(tile.tileset, header, tile, extendedId);
|
|
85
93
|
tile.children.push(childTile);
|
|
86
94
|
const frameState = this._tileManager.find(childTile.id).frameState;
|
|
87
95
|
this.updateTile(childTile, frameState);
|
|
88
96
|
|
|
89
97
|
// after tile fetched, resume traversal if still in current update/traversal frame
|
|
90
|
-
if (
|
|
98
|
+
if (
|
|
99
|
+
this._frameNumber === frameState.frameNumber &&
|
|
100
|
+
(this.traversalFinished(frameState) ||
|
|
101
|
+
new Date().getTime() - this.lastUpdate > this.updateDebounceTime)
|
|
102
|
+
) {
|
|
91
103
|
this.executeTraversal(childTile, frameState);
|
|
92
104
|
}
|
|
93
105
|
}
|
|
@@ -14,6 +14,7 @@ function defined(x) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// const scratchMatrix = new Matrix3();
|
|
17
|
+
const scratchPoint = new Vector3();
|
|
17
18
|
const scratchScale = new Vector3();
|
|
18
19
|
const scratchNorthWest = new Vector3();
|
|
19
20
|
const scratchSouthEast = new Vector3();
|
|
@@ -68,6 +69,43 @@ export function createBoundingVolume(boundingVolumeHeader, transform, result) {
|
|
|
68
69
|
throw new Error('3D Tile: boundingVolume must contain a sphere, region, or box');
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
/** [min, max] each in [longitude, latitude, altitude] */
|
|
73
|
+
export type CartographicBounds = [min: number[], max: number[]];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Calculate the cartographic bounding box the tile's bounding volume.
|
|
77
|
+
* @param {Object} boundingVolumeHeader The tile's bounding volume header.
|
|
78
|
+
* @param {BoundingVolume} boundingVolume The bounding volume.
|
|
79
|
+
* @returns {CartographicBounds}
|
|
80
|
+
*/
|
|
81
|
+
export function getCartographicBounds(
|
|
82
|
+
boundingVolumeHeader,
|
|
83
|
+
boundingVolume: OrientedBoundingBox | BoundingSphere
|
|
84
|
+
): CartographicBounds {
|
|
85
|
+
// boundingVolume schema:
|
|
86
|
+
// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/schema/boundingVolume.schema.json
|
|
87
|
+
if (boundingVolumeHeader.box) {
|
|
88
|
+
return orientedBoundingBoxToCartographicBounds(boundingVolume as OrientedBoundingBox);
|
|
89
|
+
}
|
|
90
|
+
if (boundingVolumeHeader.region) {
|
|
91
|
+
// [west, south, east, north, minimum height, maximum height]
|
|
92
|
+
// Latitudes and longitudes are in the WGS 84 datum as defined in EPSG 4979 and are in radians.
|
|
93
|
+
// Heights are in meters above (or below) the WGS 84 ellipsoid.
|
|
94
|
+
const [west, south, east, north, minHeight, maxHeight] = boundingVolumeHeader.region;
|
|
95
|
+
|
|
96
|
+
return [
|
|
97
|
+
[degrees(west), degrees(south), minHeight],
|
|
98
|
+
[degrees(east), degrees(north), maxHeight]
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (boundingVolumeHeader.sphere) {
|
|
103
|
+
return boundingSphereToCartographicBounds(boundingVolume as BoundingSphere);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
throw new Error('Unkown boundingVolume type');
|
|
107
|
+
}
|
|
108
|
+
|
|
71
109
|
function createBox(box, transform, result) {
|
|
72
110
|
// https://math.gl/modules/culling/docs/api-reference/oriented-bounding-box
|
|
73
111
|
// 1. A half-axes based representation.
|
|
@@ -197,3 +235,101 @@ function createSphere(sphere, transform, result?) {
|
|
|
197
235
|
|
|
198
236
|
return new BoundingSphere(center, radius);
|
|
199
237
|
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Convert a bounding volume defined by OrientedBoundingBox to cartographic bounds
|
|
241
|
+
* @returns {CartographicBounds}
|
|
242
|
+
*/
|
|
243
|
+
function orientedBoundingBoxToCartographicBounds(
|
|
244
|
+
boundingVolume: OrientedBoundingBox
|
|
245
|
+
): CartographicBounds {
|
|
246
|
+
const result = emptyCartographicBounds();
|
|
247
|
+
|
|
248
|
+
const {halfAxes} = boundingVolume as OrientedBoundingBox;
|
|
249
|
+
const xAxis = new Vector3(halfAxes.getColumn(0));
|
|
250
|
+
const yAxis = new Vector3(halfAxes.getColumn(1));
|
|
251
|
+
const zAxis = new Vector3(halfAxes.getColumn(2));
|
|
252
|
+
|
|
253
|
+
// Test all 8 corners of the box
|
|
254
|
+
for (let x = 0; x < 2; x++) {
|
|
255
|
+
for (let y = 0; y < 2; y++) {
|
|
256
|
+
for (let z = 0; z < 2; z++) {
|
|
257
|
+
scratchPoint.copy(boundingVolume.center);
|
|
258
|
+
scratchPoint.add(xAxis);
|
|
259
|
+
scratchPoint.add(yAxis);
|
|
260
|
+
scratchPoint.add(zAxis);
|
|
261
|
+
|
|
262
|
+
addToCartographicBounds(result, scratchPoint);
|
|
263
|
+
zAxis.negate();
|
|
264
|
+
}
|
|
265
|
+
yAxis.negate();
|
|
266
|
+
}
|
|
267
|
+
xAxis.negate();
|
|
268
|
+
}
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Convert a bounding volume defined by BoundingSphere to cartographic bounds
|
|
274
|
+
* @returns {CartographicBounds}
|
|
275
|
+
*/
|
|
276
|
+
function boundingSphereToCartographicBounds(boundingVolume: BoundingSphere): CartographicBounds {
|
|
277
|
+
const result = emptyCartographicBounds();
|
|
278
|
+
|
|
279
|
+
const {center, radius} = boundingVolume as BoundingSphere;
|
|
280
|
+
const point = Ellipsoid.WGS84.scaleToGeodeticSurface(center, scratchPoint);
|
|
281
|
+
|
|
282
|
+
let zAxis: Vector3;
|
|
283
|
+
if (point) {
|
|
284
|
+
zAxis = Ellipsoid.WGS84.geodeticSurfaceNormal(point) as Vector3;
|
|
285
|
+
} else {
|
|
286
|
+
zAxis = new Vector3(0, 0, 1);
|
|
287
|
+
}
|
|
288
|
+
let xAxis = new Vector3(zAxis[2], -zAxis[1], 0);
|
|
289
|
+
if (xAxis.len() > 0) {
|
|
290
|
+
xAxis.normalize();
|
|
291
|
+
} else {
|
|
292
|
+
xAxis = new Vector3(0, 1, 0);
|
|
293
|
+
}
|
|
294
|
+
const yAxis = xAxis.clone().cross(zAxis);
|
|
295
|
+
|
|
296
|
+
// Test 6 end points of the 3 axes
|
|
297
|
+
for (const axis of [xAxis, yAxis, zAxis]) {
|
|
298
|
+
scratchScale.copy(axis).scale(radius);
|
|
299
|
+
for (let dir = 0; dir < 2; dir++) {
|
|
300
|
+
scratchPoint.copy(center);
|
|
301
|
+
scratchPoint.add(scratchScale);
|
|
302
|
+
addToCartographicBounds(result, scratchPoint);
|
|
303
|
+
// Flip the axis
|
|
304
|
+
scratchScale.negate();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Create a new cartographic bounds that contains no points
|
|
312
|
+
* @returns {CartographicBounds}
|
|
313
|
+
*/
|
|
314
|
+
function emptyCartographicBounds(): CartographicBounds {
|
|
315
|
+
return [
|
|
316
|
+
[Infinity, Infinity, Infinity],
|
|
317
|
+
[-Infinity, -Infinity, -Infinity]
|
|
318
|
+
];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Add a point to the target cartographic bounds
|
|
323
|
+
* @param {CartographicBounds} target
|
|
324
|
+
* @param {Vector3} cartesian coordinates of the point to add
|
|
325
|
+
*/
|
|
326
|
+
function addToCartographicBounds(target: CartographicBounds, cartesian: Readonly<Vector3>) {
|
|
327
|
+
Ellipsoid.WGS84.cartesianToCartographic(cartesian, scratchPoint);
|
|
328
|
+
target[0][0] = Math.min(target[0][0], scratchPoint[0]);
|
|
329
|
+
target[0][1] = Math.min(target[0][1], scratchPoint[1]);
|
|
330
|
+
target[0][2] = Math.min(target[0][2], scratchPoint[2]);
|
|
331
|
+
|
|
332
|
+
target[1][0] = Math.max(target[1][0], scratchPoint[0]);
|
|
333
|
+
target[1][1] = Math.max(target[1][1], scratchPoint[1]);
|
|
334
|
+
target[1][2] = Math.max(target[1][2], scratchPoint[2]);
|
|
335
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import {Tile3D} from '@loaders.gl/tiles';
|
|
1
2
|
import {Vector3} from '@math.gl/core';
|
|
2
3
|
import {CullingVolume, Plane} from '@math.gl/culling';
|
|
3
4
|
import {Ellipsoid} from '@math.gl/geospatial';
|
|
5
|
+
import {GeospatialViewport, Viewport} from '../../types';
|
|
4
6
|
|
|
5
7
|
export type FrameState = {
|
|
6
8
|
camera: {
|
|
@@ -8,7 +10,8 @@ export type FrameState = {
|
|
|
8
10
|
direction: number[];
|
|
9
11
|
up: number[];
|
|
10
12
|
};
|
|
11
|
-
viewport:
|
|
13
|
+
viewport: GeospatialViewport;
|
|
14
|
+
topDownViewport: GeospatialViewport; // Use it to calculate projected radius for a tile
|
|
12
15
|
height: number;
|
|
13
16
|
cullingVolume: CullingVolume;
|
|
14
17
|
frameNumber: number; // TODO: This can be the same between updates, what number is unique for between updates?
|
|
@@ -28,18 +31,15 @@ const cullingVolume = new CullingVolume([
|
|
|
28
31
|
|
|
29
32
|
// Extracts a frame state appropriate for tile culling from a deck.gl viewport
|
|
30
33
|
// TODO - this could likely be generalized and merged back into deck.gl for other culling scenarios
|
|
31
|
-
export function getFrameState(viewport, frameNumber: number): FrameState {
|
|
34
|
+
export function getFrameState(viewport: GeospatialViewport, frameNumber: number): FrameState {
|
|
35
|
+
// Traverse and and request. Update _selectedTiles so that we know what to render.
|
|
32
36
|
// Traverse and and request. Update _selectedTiles so that we know what to render.
|
|
33
37
|
const {cameraDirection, cameraUp, height} = viewport;
|
|
34
38
|
const {metersPerUnit} = viewport.distanceScales;
|
|
35
39
|
|
|
36
|
-
const viewportCenterCartographic = [viewport.longitude, viewport.latitude, 0];
|
|
37
40
|
// TODO - Ellipsoid.eastNorthUpToFixedFrame() breaks on raw array, create a Vector.
|
|
38
41
|
// TODO - Ellipsoid.eastNorthUpToFixedFrame() takes a cartesian, is that intuitive?
|
|
39
|
-
const viewportCenterCartesian =
|
|
40
|
-
viewportCenterCartographic,
|
|
41
|
-
new Vector3()
|
|
42
|
-
);
|
|
42
|
+
const viewportCenterCartesian = worldToCartesian(viewport, viewport.center);
|
|
43
43
|
const enuToFixedTransform = Ellipsoid.WGS84.eastNorthUpToFixedFrame(viewportCenterCartesian);
|
|
44
44
|
|
|
45
45
|
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
@@ -58,7 +58,20 @@ export function getFrameState(viewport, frameNumber: number): FrameState {
|
|
|
58
58
|
enuToFixedTransform.transformAsVector(new Vector3(cameraUp).scale(metersPerUnit))
|
|
59
59
|
).normalize();
|
|
60
60
|
|
|
61
|
-
commonSpacePlanesToWGS84(viewport
|
|
61
|
+
commonSpacePlanesToWGS84(viewport);
|
|
62
|
+
|
|
63
|
+
const ViewportClass = viewport.constructor;
|
|
64
|
+
const {longitude, latitude, width, bearing, zoom} = viewport;
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
const topDownViewport = new ViewportClass({
|
|
67
|
+
longitude,
|
|
68
|
+
latitude,
|
|
69
|
+
height,
|
|
70
|
+
width,
|
|
71
|
+
bearing,
|
|
72
|
+
zoom,
|
|
73
|
+
pitch: 0
|
|
74
|
+
});
|
|
62
75
|
|
|
63
76
|
// TODO: make a file/class for frameState and document what needs to be attached to this so that traversal can function
|
|
64
77
|
return {
|
|
@@ -68,6 +81,7 @@ export function getFrameState(viewport, frameNumber: number): FrameState {
|
|
|
68
81
|
up: cameraUpCartesian
|
|
69
82
|
},
|
|
70
83
|
viewport,
|
|
84
|
+
topDownViewport,
|
|
71
85
|
height,
|
|
72
86
|
cullingVolume,
|
|
73
87
|
frameNumber, // TODO: This can be the same between updates, what number is unique for between updates?
|
|
@@ -75,25 +89,95 @@ export function getFrameState(viewport, frameNumber: number): FrameState {
|
|
|
75
89
|
};
|
|
76
90
|
}
|
|
77
91
|
|
|
78
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Limit `tiles` array length with `maximumTilesSelected` number.
|
|
94
|
+
* The criteria for this filtering is distance of a tile center
|
|
95
|
+
* to the `frameState.viewport`'s longitude and latitude
|
|
96
|
+
* @param tiles - tiles array to filter
|
|
97
|
+
* @param frameState - frameState to calculate distances
|
|
98
|
+
* @param maximumTilesSelected - maximal amount of tiles in the output array
|
|
99
|
+
* @returns new tiles array
|
|
100
|
+
*/
|
|
101
|
+
export function limitSelectedTiles(
|
|
102
|
+
tiles: Tile3D[],
|
|
103
|
+
frameState: FrameState,
|
|
104
|
+
maximumTilesSelected: number
|
|
105
|
+
): [Tile3D[], Tile3D[]] {
|
|
106
|
+
if (maximumTilesSelected === 0 || tiles.length <= maximumTilesSelected) {
|
|
107
|
+
return [tiles, []];
|
|
108
|
+
}
|
|
109
|
+
// Accumulate distances in couples array: [tileIndex: number, distanceToViewport: number]
|
|
110
|
+
const tuples: [number, number][] = [];
|
|
111
|
+
const {longitude: viewportLongitude, latitude: viewportLatitude} = frameState.viewport;
|
|
112
|
+
for (const [index, tile] of tiles.entries()) {
|
|
113
|
+
const [longitude, latitude] = tile.header.mbs;
|
|
114
|
+
const deltaLon = Math.abs(viewportLongitude - longitude);
|
|
115
|
+
const deltaLat = Math.abs(viewportLatitude - latitude);
|
|
116
|
+
const distance = Math.sqrt(deltaLat * deltaLat + deltaLon * deltaLon);
|
|
117
|
+
tuples.push([index, distance]);
|
|
118
|
+
}
|
|
119
|
+
const tuplesSorted = tuples.sort((a, b) => a[1] - b[1]);
|
|
120
|
+
const selectedTiles: Tile3D[] = [];
|
|
121
|
+
for (let i = 0; i < maximumTilesSelected; i++) {
|
|
122
|
+
selectedTiles.push(tiles[tuplesSorted[i][0]]);
|
|
123
|
+
}
|
|
124
|
+
const unselectedTiles: Tile3D[] = [];
|
|
125
|
+
for (let i = maximumTilesSelected; i < tuplesSorted.length; i++) {
|
|
126
|
+
unselectedTiles.push(tiles[tuplesSorted[i][0]]);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return [selectedTiles, unselectedTiles];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function commonSpacePlanesToWGS84(viewport) {
|
|
79
133
|
// Extract frustum planes based on current view.
|
|
80
134
|
const frustumPlanes = viewport.getFrustumPlanes();
|
|
135
|
+
|
|
136
|
+
// Get the near/far plane centers
|
|
137
|
+
const nearCenterCommon = closestPointOnPlane(frustumPlanes.near, viewport.cameraPosition);
|
|
138
|
+
const nearCenterCartesian = worldToCartesian(viewport, nearCenterCommon);
|
|
139
|
+
const cameraCartesian = worldToCartesian(viewport, viewport.cameraPosition, scratchPosition);
|
|
140
|
+
|
|
81
141
|
let i = 0;
|
|
142
|
+
cullingVolume.planes[i++].fromPointNormal(
|
|
143
|
+
nearCenterCartesian,
|
|
144
|
+
scratchVector.copy(nearCenterCartesian).subtract(cameraCartesian)
|
|
145
|
+
);
|
|
146
|
+
|
|
82
147
|
for (const dir in frustumPlanes) {
|
|
148
|
+
if (dir === 'near') {
|
|
149
|
+
continue; // eslint-disable-line no-continue
|
|
150
|
+
}
|
|
83
151
|
const plane = frustumPlanes[dir];
|
|
84
|
-
const
|
|
85
|
-
scratchPosition
|
|
86
|
-
.copy(plane.normal)
|
|
87
|
-
.scale(plane.distance - distanceToCenter)
|
|
88
|
-
.add(viewport.center);
|
|
89
|
-
const cartographicPos = viewport.unprojectPosition(scratchPosition);
|
|
90
|
-
|
|
91
|
-
const cartesianPos = Ellipsoid.WGS84.cartographicToCartesian(cartographicPos, new Vector3());
|
|
152
|
+
const posCommon = closestPointOnPlane(plane, nearCenterCommon, scratchPosition);
|
|
153
|
+
const cartesianPos = worldToCartesian(viewport, posCommon, scratchPosition);
|
|
92
154
|
|
|
93
155
|
cullingVolume.planes[i++].fromPointNormal(
|
|
94
156
|
cartesianPos,
|
|
95
157
|
// Want the normal to point into the frustum since that's what culling expects
|
|
96
|
-
scratchVector.copy(
|
|
158
|
+
scratchVector.copy(nearCenterCartesian).subtract(cartesianPos)
|
|
97
159
|
);
|
|
98
160
|
}
|
|
99
161
|
}
|
|
162
|
+
|
|
163
|
+
function closestPointOnPlane(
|
|
164
|
+
plane: {distance: number; normal: Vector3},
|
|
165
|
+
refPoint: [number, number, number] | Vector3,
|
|
166
|
+
out: Vector3 = new Vector3()
|
|
167
|
+
): Vector3 {
|
|
168
|
+
const distanceToRef = plane.normal.dot(refPoint);
|
|
169
|
+
out
|
|
170
|
+
.copy(plane.normal)
|
|
171
|
+
.scale(plane.distance - distanceToRef)
|
|
172
|
+
.add(refPoint);
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function worldToCartesian(
|
|
177
|
+
viewport: Viewport,
|
|
178
|
+
point: number[] | Vector3,
|
|
179
|
+
out: Vector3 = new Vector3()
|
|
180
|
+
): Vector3 {
|
|
181
|
+
const cartographicPos = viewport.unprojectPosition(point);
|
|
182
|
+
return Ellipsoid.WGS84.cartographicToCartesian(cartographicPos, out);
|
|
183
|
+
}
|