@loaders.gl/tiles 3.1.6 → 3.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.
Files changed (33) hide show
  1. package/dist/dist.min.js +834 -294
  2. package/dist/es5/tileset/helpers/frame-state.js +79 -0
  3. package/dist/es5/tileset/helpers/frame-state.js.map +1 -1
  4. package/dist/es5/tileset/helpers/i3s-lod.js +17 -26
  5. package/dist/es5/tileset/helpers/i3s-lod.js.map +1 -1
  6. package/dist/es5/tileset/tile-3d.js +5 -0
  7. package/dist/es5/tileset/tile-3d.js.map +1 -1
  8. package/dist/es5/tileset/tileset-3d.js +152 -71
  9. package/dist/es5/tileset/tileset-3d.js.map +1 -1
  10. package/dist/esm/tileset/helpers/frame-state.js +52 -0
  11. package/dist/esm/tileset/helpers/frame-state.js.map +1 -1
  12. package/dist/esm/tileset/helpers/i3s-lod.js +17 -27
  13. package/dist/esm/tileset/helpers/i3s-lod.js.map +1 -1
  14. package/dist/esm/tileset/tile-3d.js +4 -0
  15. package/dist/esm/tileset/tile-3d.js.map +1 -1
  16. package/dist/esm/tileset/tileset-3d.js +41 -9
  17. package/dist/esm/tileset/tileset-3d.js.map +1 -1
  18. package/dist/tileset/helpers/frame-state.d.ts +14 -0
  19. package/dist/tileset/helpers/frame-state.d.ts.map +1 -1
  20. package/dist/tileset/helpers/frame-state.js +49 -1
  21. package/dist/tileset/helpers/i3s-lod.d.ts.map +1 -1
  22. package/dist/tileset/helpers/i3s-lod.js +17 -16
  23. package/dist/tileset/tile-3d.d.ts +5 -0
  24. package/dist/tileset/tile-3d.d.ts.map +1 -1
  25. package/dist/tileset/tile-3d.js +7 -0
  26. package/dist/tileset/tileset-3d.d.ts +19 -1
  27. package/dist/tileset/tileset-3d.d.ts.map +1 -1
  28. package/dist/tileset/tileset-3d.js +46 -8
  29. package/package.json +5 -5
  30. package/src/tileset/helpers/frame-state.ts +56 -0
  31. package/src/tileset/helpers/i3s-lod.ts +18 -19
  32. package/src/tileset/tile-3d.ts +8 -0
  33. package/src/tileset/tileset-3d.ts +57 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/tiles",
3
- "version": "3.1.6",
3
+ "version": "3.2.0-alpha.1",
4
4
  "description": "Common components for different tiles loaders.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -33,8 +33,8 @@
33
33
  "build-bundle": "esbuild src/bundle.ts --bundle --outfile=dist/dist.min.js"
34
34
  },
35
35
  "dependencies": {
36
- "@loaders.gl/loader-utils": "3.1.6",
37
- "@loaders.gl/math": "3.1.6",
36
+ "@loaders.gl/loader-utils": "3.2.0-alpha.1",
37
+ "@loaders.gl/math": "3.2.0-alpha.1",
38
38
  "@math.gl/core": "^3.5.1",
39
39
  "@math.gl/culling": "^3.5.1",
40
40
  "@math.gl/geospatial": "^3.5.1",
@@ -42,7 +42,7 @@
42
42
  "@probe.gl/stats": "^3.5.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@loaders.gl/core": "3.1.0"
45
+ "@loaders.gl/core": "4.0.0-alpha.4"
46
46
  },
47
- "gitHead": "4fe0724b942697a95ff3eb3af47b7a7c18556c52"
47
+ "gitHead": "423a2815092b08dcf93ad5b7dc2940b167305afe"
48
48
  }
@@ -1,3 +1,4 @@
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';
@@ -9,6 +10,7 @@ export type FrameState = {
9
10
  up: number[];
10
11
  };
11
12
  viewport: {[key: string]: any};
13
+ topDownViewport: {[key: string]: any}; // Use it to calculate projected radius for a tile
12
14
  height: number;
13
15
  cullingVolume: CullingVolume;
14
16
  frameNumber: number; // TODO: This can be the same between updates, what number is unique for between updates?
@@ -60,6 +62,19 @@ export function getFrameState(viewport, frameNumber: number): FrameState {
60
62
 
61
63
  commonSpacePlanesToWGS84(viewport, viewportCenterCartesian);
62
64
 
65
+ const ViewportClass = viewport.constructor;
66
+ const {longitude, latitude, width, bearing, zoom} = viewport;
67
+ // @ts-ignore
68
+ const topDownViewport = new ViewportClass({
69
+ longitude,
70
+ latitude,
71
+ height,
72
+ width,
73
+ bearing,
74
+ zoom,
75
+ pitch: 0
76
+ });
77
+
63
78
  // TODO: make a file/class for frameState and document what needs to be attached to this so that traversal can function
64
79
  return {
65
80
  camera: {
@@ -68,6 +83,7 @@ export function getFrameState(viewport, frameNumber: number): FrameState {
68
83
  up: cameraUpCartesian
69
84
  },
70
85
  viewport,
86
+ topDownViewport,
71
87
  height,
72
88
  cullingVolume,
73
89
  frameNumber, // TODO: This can be the same between updates, what number is unique for between updates?
@@ -75,6 +91,46 @@ export function getFrameState(viewport, frameNumber: number): FrameState {
75
91
  };
76
92
  }
77
93
 
94
+ /**
95
+ * Limit `tiles` array length with `maximumTilesSelected` number.
96
+ * The criteria for this filtering is distance of a tile center
97
+ * to the `frameState.viewport`'s longitude and latitude
98
+ * @param tiles - tiles array to filter
99
+ * @param frameState - frameState to calculate distances
100
+ * @param maximumTilesSelected - maximal amount of tiles in the output array
101
+ * @returns new tiles array
102
+ */
103
+ export function limitSelectedTiles(
104
+ tiles: Tile3D[],
105
+ frameState: FrameState,
106
+ maximumTilesSelected: number
107
+ ): [Tile3D[], Tile3D[]] {
108
+ if (maximumTilesSelected === 0 || tiles.length <= maximumTilesSelected) {
109
+ return [tiles, []];
110
+ }
111
+ // Accumulate distances in couples array: [tileIndex: number, distanceToViewport: number]
112
+ const tuples: [number, number][] = [];
113
+ const {longitude: viewportLongitude, latitude: viewportLatitude} = frameState.viewport;
114
+ for (const [index, tile] of tiles.entries()) {
115
+ const [longitude, latitude] = tile.header.mbs;
116
+ const deltaLon = Math.abs(viewportLongitude - longitude);
117
+ const deltaLat = Math.abs(viewportLatitude - latitude);
118
+ const distance = Math.sqrt(deltaLat * deltaLat + deltaLon * deltaLon);
119
+ tuples.push([index, distance]);
120
+ }
121
+ const tuplesSorted = tuples.sort((a, b) => a[1] - b[1]);
122
+ const selectedTiles: Tile3D[] = [];
123
+ for (let i = 0; i < maximumTilesSelected; i++) {
124
+ selectedTiles.push(tiles[tuplesSorted[i][0]]);
125
+ }
126
+ const unselectedTiles: Tile3D[] = [];
127
+ for (let i = maximumTilesSelected; i < tuplesSorted.length; i++) {
128
+ unselectedTiles.push(tiles[tuplesSorted[i][0]]);
129
+ }
130
+
131
+ return [selectedTiles, unselectedTiles];
132
+ }
133
+
78
134
  function commonSpacePlanesToWGS84(viewport, viewportCenterCartesian) {
79
135
  // Extract frustum planes based on current view.
80
136
  const frustumPlanes = viewport.getFrustumPlanes();
@@ -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 originalViewport = frameState.viewport;
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
- const cameraPositionCartesian = Ellipsoid.WGS84.cartographicToCartesian(
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
- const toEye = new Vector3(cameraPositionCartesian).subtract(mbsCenterCartesian).normalize();
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
- const cartesianToEnuMatrix = new Matrix4(enuToCartesianMatrix).invert();
63
- const cameraPositionEnu = new Vector3(cameraPositionCartesian).transform(cartesianToEnuMatrix);
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
- const extraVertexEnu = new Vector3([cameraPositionEnu[0], cameraPositionEnu[1], extraZ]);
70
+ extraVertexEnu.copy([cameraPositionEnu[0], cameraPositionEnu[1], extraZ]);
71
71
  const extraVertexCartesian = extraVertexEnu.transform(enuToCartesianMatrix);
72
- const extraVectorCartesian = new Vector3(extraVertexCartesian)
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 = new Vector3(mbsCenterCartesian).add(radiusVector);
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 = new Vector3(projectedOrigin)
84
+ const projectedRadius = projectedOriginVector
85
+ .copy(projectedOrigin)
87
86
  .subtract(projectedMbsBorderVertex)
88
87
  .magnitude();
89
88
  return projectedRadius;
@@ -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,7 +48,7 @@ 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';
51
+ import {FrameState, getFrameState, limitSelectedTiles} from './helpers/frame-state';
52
52
  import {getZoomFromBoundingVolume} from './helpers/zoom';
53
53
  import Tile3D from './tile-3d';
54
54
  import Tileset3DTraverser from './traversers/tileset-3d-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
@@ -207,6 +215,7 @@ export default class Tileset3D {
207
215
  traverseCounter: number;
208
216
  geometricError: number;
209
217
  selectedTiles: Tile3D[];
218
+ private updatePromise: Promise<number> | null = null;
210
219
 
211
220
  cartographicCenter: Vector3 | null;
212
221
  cartesianCenter: Vector3 | null;
@@ -382,20 +391,51 @@ 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
+ if (!viewports && this.lastUpdatedVieports) {
398
+ viewports = this.lastUpdatedVieports;
399
+ } else {
400
+ this.lastUpdatedVieports = viewports;
401
+ }
402
+ this.doUpdate(viewports);
403
+ }
404
+
405
+ /**
406
+ * Update visible tiles relying on a list of viewports.
407
+ * Do it with debounce delay to prevent update spam
408
+ * @param viewports viewports
409
+ * @returns Promise of new frameNumber
410
+ */
411
+ async selectTiles(viewports: any[] | null = null): Promise<number> {
412
+ if (viewports) {
413
+ this.lastUpdatedVieports = viewports;
414
+ }
415
+ if (!this.updatePromise) {
416
+ this.updatePromise = new Promise<number>((resolve) => {
417
+ setTimeout(() => {
418
+ this.doUpdate(this.lastUpdatedVieports);
419
+ resolve(this._frameNumber);
420
+ this.updatePromise = null;
421
+ }, this.options.debounceTime);
422
+ });
423
+ }
424
+ return this.updatePromise;
425
+ }
426
+
427
+ /**
428
+ * Update visible tiles relying on a list of viewports
429
+ * @param viewports viewports
385
430
  */
386
431
  // eslint-disable-next-line max-statements, complexity
387
- update(viewports: any[]): void {
432
+ private doUpdate(viewports: any[] | null = null): void {
388
433
  if ('loadTiles' in this.options && !this.options.loadTiles) {
389
434
  return;
390
435
  }
391
436
  if (this.traverseCounter > 0) {
392
437
  return;
393
438
  }
394
- if (!viewports && this.lastUpdatedVieports) {
395
- viewports = this.lastUpdatedVieports;
396
- } else {
397
- this.lastUpdatedVieports = viewports;
398
- }
399
439
  if (!(viewports instanceof Array)) {
400
440
  viewports = [viewports];
401
441
  }
@@ -457,7 +497,16 @@ export default class Tileset3D {
457
497
  }
458
498
  const currentFrameStateData = this.frameStateData[id];
459
499
  const selectedTiles = Object.values(this._traverser.selectedTiles);
460
- currentFrameStateData.selectedTiles = selectedTiles;
500
+ const [filteredSelectedTiles, unselectedTiles] = limitSelectedTiles(
501
+ selectedTiles,
502
+ frameState,
503
+ this.options.maximumTilesSelected
504
+ );
505
+ currentFrameStateData.selectedTiles = filteredSelectedTiles;
506
+ for (const tile of unselectedTiles) {
507
+ tile.unselect();
508
+ }
509
+
461
510
  currentFrameStateData._requestedTiles = Object.values(this._traverser.requestedTiles);
462
511
  currentFrameStateData._emptyTiles = Object.values(this._traverser.emptyTiles);
463
512