astro-viewer 3.0.0 → 3.2.0
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/astroviewer.cjs +3082 -1410
- package/dist/astroviewer.js +1 -1
- package/dist/astroviewer.min.js +1 -1
- package/lib-esm/AstroSphere.d.ts +40 -16
- package/lib-esm/AstroSphere.js +359 -93
- package/lib-esm/AstroViewer.d.ts +20 -5
- package/lib-esm/AstroViewer.js +50 -0
- package/lib-esm/Camera.js +28 -14
- package/lib-esm/Config.d.ts +2 -0
- package/lib-esm/Config.js +15 -1
- package/lib-esm/Global.js +12 -0
- package/lib-esm/index.d.ts +8 -4
- package/lib-esm/index.js +17 -3
- package/lib-esm/model/AbstractSkyEntity.d.ts +1 -0
- package/lib-esm/model/AbstractSkyEntity.js +12 -0
- package/lib-esm/model/AstroGL.js +12 -0
- package/lib-esm/model/ColorMaps.js +12 -0
- package/lib-esm/model/MetadataColumn.js +12 -0
- package/lib-esm/model/MetadataManager.d.ts +1 -0
- package/lib-esm/model/MetadataManager.js +16 -1
- package/lib-esm/model/Point.d.ts +9 -1
- package/lib-esm/model/Point.js +30 -0
- package/lib-esm/model/Point2D.js +12 -0
- package/lib-esm/model/Source.js +12 -0
- package/lib-esm/model/SphereFoV.d.ts +30 -0
- package/lib-esm/model/SphereFoV.js +196 -0
- package/lib-esm/model/catalogues/CatalogueGL.js +12 -0
- package/lib-esm/model/catalogues/CatalogueProps.js +13 -1
- package/lib-esm/model/earth/{wmts/WMTSAdapter.d.ts → WMTSAdapter.d.ts} +2 -1
- package/lib-esm/model/earth/{wmts/WMTSAdapter.js → WMTSAdapter.js} +12 -0
- package/lib-esm/model/earth/XYZAnchestorTile.d.ts +17 -0
- package/lib-esm/model/earth/XYZAnchestorTile.js +87 -0
- package/lib-esm/model/earth/{types.d.ts → XYZConfig.d.ts} +6 -17
- package/lib-esm/model/earth/XYZConfig.js +13 -0
- package/lib-esm/model/earth/XYZFoVHelper.d.ts +12 -0
- package/lib-esm/model/earth/XYZFoVHelper.js +138 -0
- package/lib-esm/model/earth/XYZMap.d.ts +31 -0
- package/lib-esm/model/earth/XYZMap.js +208 -0
- package/lib-esm/model/earth/XYZMapDescriptor.d.ts +29 -0
- package/lib-esm/model/earth/XYZMapDescriptor.js +77 -0
- package/lib-esm/model/earth/XYZMeshBuilder.d.ts +1 -1
- package/lib-esm/model/earth/XYZMeshBuilder.js +13 -2
- package/lib-esm/model/earth/XYZTile.d.ts +20 -21
- package/lib-esm/model/earth/XYZTile.js +82 -102
- package/lib-esm/model/earth/XYZTileBuffer.d.ts +24 -26
- package/lib-esm/model/earth/XYZTileBuffer.js +60 -70
- package/lib-esm/model/earth/XYZTileRequestScheduler.d.ts +1 -1
- package/lib-esm/model/earth/XYZTileRequestScheduler.js +13 -2
- package/lib-esm/model/earth/XYZTypes.d.ts +24 -0
- package/lib-esm/model/earth/XYZTypes.js +13 -0
- package/lib-esm/model/earth/XYZVisibleTilesManager.d.ts +16 -27
- package/lib-esm/model/earth/XYZVisibleTilesManager.js +61 -192
- package/lib-esm/model/footprints/Footprint.d.ts +4 -1
- package/lib-esm/model/footprints/Footprint.js +30 -2
- package/lib-esm/model/footprints/FootprintProps.js +13 -1
- package/lib-esm/model/footprints/FootprintSetGL.d.ts +4 -2
- package/lib-esm/model/footprints/FootprintSetGL.js +21 -6
- package/lib-esm/model/grid/EquatorialGrid.d.ts +2 -1
- package/lib-esm/model/grid/EquatorialGrid.js +30 -12
- package/lib-esm/model/grid/GridTextHelper.d.ts +10 -19
- package/lib-esm/model/grid/GridTextHelper.js +70 -67
- package/lib-esm/model/grid/HealpixGrid.d.ts +4 -4
- package/lib-esm/model/grid/HealpixGrid.js +24 -8
- package/lib-esm/model/grid/LonLatGrid.d.ts +43 -0
- package/lib-esm/model/grid/LonLatGrid.js +309 -0
- package/lib-esm/model/hips/AllSky.js +12 -0
- package/lib-esm/model/hips/AncestorTile.js +12 -0
- package/lib-esm/model/hips/FoVHelper.d.ts +5 -2
- package/lib-esm/model/hips/FoVHelper.js +52 -3
- package/lib-esm/model/hips/HiPS.d.ts +2 -0
- package/lib-esm/model/hips/HiPS.js +38 -14
- package/lib-esm/model/hips/HiPSConfig.d.ts +13 -0
- package/lib-esm/model/hips/HiPSDescriptor.js +12 -0
- package/lib-esm/model/hips/Tile.d.ts +1 -0
- package/lib-esm/model/hips/Tile.js +15 -0
- package/lib-esm/model/hips/TileBuffer.d.ts +5 -0
- package/lib-esm/model/hips/TileBuffer.js +61 -0
- package/lib-esm/model/hips/VisibleTilesManager.js +12 -0
- package/lib-esm/model/tap/TapMetadata.js +12 -0
- package/lib-esm/model/tap/TapMetadataList.js +12 -0
- package/lib-esm/model/tap/TapRepo.js +12 -0
- package/lib-esm/model/terra/TerraFootprintSetGL.d.ts +6 -0
- package/lib-esm/model/terra/TerraFootprintSetGL.js +54 -0
- package/lib-esm/model/terra/TerraPointSetGL.js +12 -0
- package/lib-esm/services/SesameService.js +11 -3
- package/lib-esm/services/helpers.js +12 -0
- package/lib-esm/services/hipsNodeService.js +12 -0
- package/lib-esm/services/parse-hipslist.js +12 -0
- package/lib-esm/services/queryCatalogueByFoV.js +13 -1
- package/lib-esm/services/queryFootprintSetByFov.js +13 -1
- package/lib-esm/services/tapRepoService.js +13 -1
- package/lib-esm/services/types.js +12 -0
- package/lib-esm/shader/CatalogueShaderProgram.js +12 -0
- package/lib-esm/shader/FootprintShaderProgram.js +12 -0
- package/lib-esm/shader/GridShaderManager.js +12 -0
- package/lib-esm/shader/HiPSShaderProgram.js +12 -0
- package/lib-esm/shader/ShaderManager.js +12 -1
- package/lib-esm/shader/ShaderManagerMutliHiPS.js +12 -1
- package/lib-esm/shader/XYZShaderProgram.d.ts +14 -1
- package/lib-esm/shader/XYZShaderProgram.js +127 -2
- package/lib-esm/utils/CoordsType.d.ts +2 -1
- package/lib-esm/utils/CoordsType.js +13 -0
- package/lib-esm/utils/FoVUtils.js +12 -0
- package/lib-esm/utils/GeoJSONParser.d.ts +19 -0
- package/lib-esm/utils/GeoJSONParser.js +112 -0
- package/lib-esm/utils/GeomUtils.js +12 -0
- package/lib-esm/utils/MouseHelper.js +12 -0
- package/lib-esm/utils/PerspectiveMatrixManager.js +16 -1
- package/lib-esm/utils/RayPickingUtils.js +12 -0
- package/lib-esm/utils/STCSParser.d.ts +7 -3
- package/lib-esm/utils/STCSParser.js +27 -9
- package/lib-esm/utils/ShaderUtility.js +13 -1
- package/lib-esm/utils/Utils.js +12 -0
- package/lib-esm/utils/XYZRayPickingUtils.d.ts +27 -0
- package/lib-esm/utils/XYZRayPickingUtils.js +226 -0
- package/package.json +2 -2
- package/lib-esm/model/FoV.d.ts +0 -62
- package/lib-esm/model/FoV.js +0 -274
- package/lib-esm/model/earth/XYZAncestorMeshCache.d.ts +0 -10
- package/lib-esm/model/earth/XYZAncestorMeshCache.js +0 -31
- package/lib-esm/model/earth/XYZLayer.d.ts +0 -31
- package/lib-esm/model/earth/XYZLayer.js +0 -231
- package/lib-esm/model/earth/XYZTileProvider.d.ts +0 -29
- package/lib-esm/model/earth/XYZTileProvider.js +0 -187
- package/lib-esm/model/earth/wmts/types.d.ts +0 -1
- package/lib-esm/model/earth/wmts/types.js +0 -1
- /package/lib-esm/model/{earth/types.js → hips/HiPSConfig.js} +0 -0
|
@@ -1,39 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
role: 'current' | 'coverage' | 'fallback' | 'base';
|
|
1
|
+
import type { XYZTileCoord } from './XYZTypes.js';
|
|
2
|
+
export type XYZBufferedTile = {
|
|
3
|
+
coord: XYZTileCoord;
|
|
4
|
+
loading?: boolean;
|
|
5
|
+
lastUsedAt?: number;
|
|
6
|
+
createdAt?: number;
|
|
7
|
+
touch?: () => void;
|
|
8
|
+
dispose?: () => void;
|
|
10
9
|
};
|
|
11
|
-
type XYZTileBufferEntry = {
|
|
12
|
-
tile:
|
|
10
|
+
export type XYZTileBufferEntry<TTile extends XYZBufferedTile = XYZBufferedTile> = {
|
|
11
|
+
tile: TTile;
|
|
13
12
|
cacheTime0?: number;
|
|
14
|
-
role: 'current' | 'coverage' | 'fallback' | 'base';
|
|
15
13
|
};
|
|
16
|
-
export
|
|
14
|
+
export type XYZTileFactory<TTile extends XYZBufferedTile = XYZBufferedTile> = (coord: XYZTileCoord) => TTile;
|
|
15
|
+
export declare class XYZTileBuffer<TTile extends XYZBufferedTile = XYZBufferedTile> {
|
|
17
16
|
private _tiles;
|
|
18
17
|
private _cachedTiles;
|
|
19
18
|
private _cacheAliveMilliSeconds;
|
|
20
19
|
private _cleanerId;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
constructor(minutesToLiveInCache: number | undefined, webgl: WebGL2RenderingContext, meshBuilder: XYZMeshBuilder, shaderProgram: XYZShaderProgram);
|
|
25
|
-
get activeTiles(): Map<string, XYZTileBufferEntry>;
|
|
26
|
-
get cachedTiles(): Map<string, XYZTileBufferEntry>;
|
|
20
|
+
constructor(minutesToLiveInCache?: number);
|
|
21
|
+
get activeTiles(): Map<string, XYZTileBufferEntry<TTile>>;
|
|
22
|
+
get cachedTiles(): Map<string, XYZTileBufferEntry<TTile>>;
|
|
27
23
|
get size(): number;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
ensureTiles(visibleTiles: XYZTileCoord[], tileFactory: XYZTileFactory<TTile>): string[];
|
|
25
|
+
getTile(tileCoord: XYZTileCoord, tileFactory: XYZTileFactory<TTile>): TTile;
|
|
26
|
+
getActiveTile(tileKey: string): TTile | null;
|
|
27
|
+
getAnyTile(tileKey: string): TTile | null;
|
|
28
|
+
getActiveTiles(): TTile[];
|
|
33
29
|
syncVisibleTiles(visibleTileKeys: string[]): void;
|
|
34
30
|
evictCached(maxCachedTiles: number): void;
|
|
35
31
|
dispose(): void;
|
|
32
|
+
key(tileCoord: XYZTileCoord): string;
|
|
33
|
+
static key(tileCoord: XYZTileCoord): string;
|
|
36
34
|
private cacheCleaner;
|
|
37
|
-
private
|
|
35
|
+
private touchTile;
|
|
36
|
+
private getTileAgeScore;
|
|
38
37
|
}
|
|
39
|
-
export {};
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
* AstroViewer
|
|
3
|
+
* Copyright (C) Fabrizio Giordano
|
|
4
|
+
* SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
|
|
5
|
+
*
|
|
6
|
+
* This file is part of AstroViewer.
|
|
7
|
+
* AstroViewer is distributed under a dual-license model.
|
|
8
|
+
* Commercial use requires a separate commercial license.
|
|
9
|
+
* Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
|
|
10
|
+
*
|
|
11
|
+
* See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
|
|
12
|
+
*/
|
|
2
13
|
export class XYZTileBuffer {
|
|
3
14
|
_tiles = new Map();
|
|
4
15
|
_cachedTiles = new Map();
|
|
5
16
|
_cacheAliveMilliSeconds;
|
|
6
17
|
_cleanerId;
|
|
7
|
-
|
|
8
|
-
_meshBuilder;
|
|
9
|
-
_shaderProgram;
|
|
10
|
-
constructor(minutesToLiveInCache = 1, webgl, meshBuilder, shaderProgram) {
|
|
18
|
+
constructor(minutesToLiveInCache = 1) {
|
|
11
19
|
this._cacheAliveMilliSeconds = minutesToLiveInCache * 60 * 1000;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}, 10_000);
|
|
20
|
+
if (typeof window !== 'undefined') {
|
|
21
|
+
this._cleanerId = window.setInterval(() => {
|
|
22
|
+
this.cacheCleaner();
|
|
23
|
+
}, 10_000);
|
|
24
|
+
}
|
|
18
25
|
}
|
|
19
26
|
get activeTiles() {
|
|
20
27
|
return this._tiles;
|
|
@@ -25,64 +32,31 @@ export class XYZTileBuffer {
|
|
|
25
32
|
get size() {
|
|
26
33
|
return this._tiles.size + this._cachedTiles.size;
|
|
27
34
|
}
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
entry.role = role;
|
|
35
|
-
this._tiles.set(tileKey, entry);
|
|
36
|
-
this._cachedTiles.delete(tileKey);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
const mesh = this._meshBuilder.buildTileMesh(tileCoord, segmentsPerSide);
|
|
40
|
-
this._tiles.set(tileKey, {
|
|
41
|
-
tile: new XYZTile(tileCoord, url, mesh, this._webgl, this._shaderProgram),
|
|
42
|
-
role,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
const entry = this._tiles.get(tileKey);
|
|
48
|
-
entry.role = role;
|
|
35
|
+
ensureTiles(visibleTiles, tileFactory) {
|
|
36
|
+
const visibleTileKeys = [];
|
|
37
|
+
for (const tileCoord of visibleTiles) {
|
|
38
|
+
const tile = this.getTile(tileCoord, tileFactory);
|
|
39
|
+
this.touchTile(tile);
|
|
40
|
+
visibleTileKeys.push(this.key(tileCoord));
|
|
49
41
|
}
|
|
50
|
-
|
|
42
|
+
this.syncVisibleTiles(visibleTileKeys);
|
|
43
|
+
return visibleTileKeys;
|
|
51
44
|
}
|
|
52
|
-
|
|
45
|
+
getTile(tileCoord, tileFactory) {
|
|
53
46
|
const tileKey = this.key(tileCoord);
|
|
54
47
|
if (this._tiles.has(tileKey)) {
|
|
55
|
-
|
|
56
|
-
entry.role = role;
|
|
57
|
-
return entry.tile;
|
|
48
|
+
return this._tiles.get(tileKey).tile;
|
|
58
49
|
}
|
|
59
50
|
if (this._cachedTiles.has(tileKey)) {
|
|
60
51
|
const entry = this._cachedTiles.get(tileKey);
|
|
61
52
|
entry.cacheTime0 = undefined;
|
|
62
|
-
entry.role = role;
|
|
63
53
|
this._tiles.set(tileKey, entry);
|
|
64
54
|
this._cachedTiles.delete(tileKey);
|
|
65
55
|
return entry.tile;
|
|
66
56
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const visibleTileKeys = [];
|
|
71
|
-
for (const request of requests) {
|
|
72
|
-
const tile = request.role === 'fallback'
|
|
73
|
-
? this.getExistingTile(request.tileCoord, 'fallback')
|
|
74
|
-
: this.getTile(request.tileCoord, request.url, segmentsPerSide, request.role);
|
|
75
|
-
if (!tile) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
tile.touch();
|
|
79
|
-
if (request.role !== 'fallback') {
|
|
80
|
-
tile.primeLoad(request.priority);
|
|
81
|
-
}
|
|
82
|
-
visibleTileKeys.push(this.key(request.tileCoord));
|
|
83
|
-
}
|
|
84
|
-
this.syncVisibleTiles(visibleTileKeys);
|
|
85
|
-
return visibleTileKeys;
|
|
57
|
+
const tile = tileFactory(tileCoord);
|
|
58
|
+
this._tiles.set(tileKey, { tile });
|
|
59
|
+
return tile;
|
|
86
60
|
}
|
|
87
61
|
getActiveTile(tileKey) {
|
|
88
62
|
return this._tiles.get(tileKey)?.tile ?? null;
|
|
@@ -90,11 +64,14 @@ export class XYZTileBuffer {
|
|
|
90
64
|
getAnyTile(tileKey) {
|
|
91
65
|
return this._tiles.get(tileKey)?.tile ?? this._cachedTiles.get(tileKey)?.tile ?? null;
|
|
92
66
|
}
|
|
67
|
+
getActiveTiles() {
|
|
68
|
+
return Array.from(this._tiles.values(), (entry) => entry.tile);
|
|
69
|
+
}
|
|
93
70
|
syncVisibleTiles(visibleTileKeys) {
|
|
94
71
|
const visibleKeySet = new Set(visibleTileKeys);
|
|
95
72
|
for (const [tileKey, entry] of this._tiles) {
|
|
96
73
|
if (visibleKeySet.has(tileKey)) {
|
|
97
|
-
entry.tile
|
|
74
|
+
this.touchTile(entry.tile);
|
|
98
75
|
continue;
|
|
99
76
|
}
|
|
100
77
|
entry.cacheTime0 = Date.now();
|
|
@@ -107,9 +84,7 @@ export class XYZTileBuffer {
|
|
|
107
84
|
return;
|
|
108
85
|
}
|
|
109
86
|
const candidates = Array.from(this._cachedTiles.entries()).sort((a, b) => {
|
|
110
|
-
|
|
111
|
-
const scoreB = Math.min(b[1].tile.lastUsedAt || b[1].tile.createdAt, b[1].tile.createdAt);
|
|
112
|
-
return scoreA - scoreB;
|
|
87
|
+
return this.getTileAgeScore(a[1].tile) - this.getTileAgeScore(b[1].tile);
|
|
113
88
|
});
|
|
114
89
|
for (const [tileKey, entry] of candidates) {
|
|
115
90
|
if (this.size <= maxCachedTiles) {
|
|
@@ -118,32 +93,47 @@ export class XYZTileBuffer {
|
|
|
118
93
|
if (entry.tile.loading) {
|
|
119
94
|
continue;
|
|
120
95
|
}
|
|
121
|
-
entry.tile.dispose();
|
|
96
|
+
entry.tile.dispose?.();
|
|
122
97
|
this._cachedTiles.delete(tileKey);
|
|
123
98
|
}
|
|
124
99
|
}
|
|
125
100
|
dispose() {
|
|
126
|
-
|
|
101
|
+
if (this._cleanerId !== undefined && typeof window !== 'undefined') {
|
|
102
|
+
window.clearInterval(this._cleanerId);
|
|
103
|
+
this._cleanerId = undefined;
|
|
104
|
+
}
|
|
127
105
|
for (const entry of this._tiles.values()) {
|
|
128
|
-
entry.tile.dispose();
|
|
106
|
+
entry.tile.dispose?.();
|
|
129
107
|
}
|
|
130
108
|
for (const entry of this._cachedTiles.values()) {
|
|
131
|
-
entry.tile.dispose();
|
|
109
|
+
entry.tile.dispose?.();
|
|
132
110
|
}
|
|
133
111
|
this._tiles.clear();
|
|
134
112
|
this._cachedTiles.clear();
|
|
135
113
|
}
|
|
114
|
+
key(tileCoord) {
|
|
115
|
+
return XYZTileBuffer.key(tileCoord);
|
|
116
|
+
}
|
|
117
|
+
static key(tileCoord) {
|
|
118
|
+
return `${tileCoord.z}/${tileCoord.x}/${tileCoord.y}`;
|
|
119
|
+
}
|
|
136
120
|
cacheCleaner() {
|
|
137
121
|
const now = Date.now();
|
|
138
122
|
for (const [tileKey, entry] of this._cachedTiles) {
|
|
139
123
|
const t0 = entry.cacheTime0;
|
|
140
|
-
if (t0
|
|
141
|
-
|
|
142
|
-
this._cachedTiles.delete(tileKey);
|
|
124
|
+
if (t0 === undefined || now - t0 <= this._cacheAliveMilliSeconds || entry.tile.loading) {
|
|
125
|
+
continue;
|
|
143
126
|
}
|
|
127
|
+
entry.tile.dispose?.();
|
|
128
|
+
this._cachedTiles.delete(tileKey);
|
|
144
129
|
}
|
|
145
130
|
}
|
|
146
|
-
|
|
147
|
-
|
|
131
|
+
touchTile(tile) {
|
|
132
|
+
tile.touch?.();
|
|
133
|
+
}
|
|
134
|
+
getTileAgeScore(tile) {
|
|
135
|
+
const lastUsedAt = tile.lastUsedAt ?? 0;
|
|
136
|
+
const createdAt = tile.createdAt ?? lastUsedAt;
|
|
137
|
+
return Math.min(lastUsedAt || createdAt, createdAt);
|
|
148
138
|
}
|
|
149
139
|
}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AstroViewer
|
|
3
|
+
* Copyright (C) Fabrizio Giordano
|
|
4
|
+
* SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
|
|
5
|
+
*
|
|
6
|
+
* This file is part of AstroViewer.
|
|
7
|
+
* AstroViewer is distributed under a dual-license model.
|
|
8
|
+
* Commercial use requires a separate commercial license.
|
|
9
|
+
* Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
|
|
10
|
+
*
|
|
11
|
+
* See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
|
|
12
|
+
*/
|
|
1
13
|
export class XYZTileRequestError extends Error {
|
|
2
14
|
cooldownMs;
|
|
3
15
|
retryable;
|
|
@@ -73,9 +85,8 @@ export class XYZTileRequestScheduler {
|
|
|
73
85
|
pump() {
|
|
74
86
|
while (this._activeCount < this._maxConcurrent && this._queue.length > 0) {
|
|
75
87
|
const item = this._queue.shift();
|
|
76
|
-
if (!item)
|
|
88
|
+
if (!item)
|
|
77
89
|
return;
|
|
78
|
-
}
|
|
79
90
|
const hostCooldown = this.getHostCooldown(item.url);
|
|
80
91
|
const now = Date.now();
|
|
81
92
|
if (hostCooldown > now) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type XYZTileCoord = {
|
|
2
|
+
z: number;
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
};
|
|
6
|
+
export type XYZVisibleTileSelection = {
|
|
7
|
+
key: string;
|
|
8
|
+
currentZoom: number;
|
|
9
|
+
visibleTiles: XYZTileCoord[];
|
|
10
|
+
visibleTilesMap: Map<string, XYZTileCoord>;
|
|
11
|
+
ancestorsMap: Map<string, XYZTileCoord>;
|
|
12
|
+
};
|
|
13
|
+
export type XYZTileMesh = {
|
|
14
|
+
positions: Float32Array;
|
|
15
|
+
uvs: Float32Array;
|
|
16
|
+
indices: Uint16Array | Uint32Array;
|
|
17
|
+
};
|
|
18
|
+
export type XYZTileGpuMesh = {
|
|
19
|
+
positionBuffer: WebGLBuffer | null;
|
|
20
|
+
uvBuffer: WebGLBuffer | null;
|
|
21
|
+
indexBuffer: WebGLBuffer | null;
|
|
22
|
+
indexCount: number;
|
|
23
|
+
indexType: number;
|
|
24
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AstroViewer
|
|
3
|
+
* Copyright (C) Fabrizio Giordano
|
|
4
|
+
* SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
|
|
5
|
+
*
|
|
6
|
+
* This file is part of AstroViewer.
|
|
7
|
+
* AstroViewer is distributed under a dual-license model.
|
|
8
|
+
* Commercial use requires a separate commercial license.
|
|
9
|
+
* Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
|
|
10
|
+
*
|
|
11
|
+
* See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
key: string;
|
|
6
|
-
currentTiles: XYZTileCoord[];
|
|
7
|
-
fallbackTiles: XYZTileCoord[];
|
|
8
|
-
currentZoom: number;
|
|
9
|
-
coreTileCount: number;
|
|
10
|
-
coverageTileCount: number;
|
|
11
|
-
};
|
|
1
|
+
import { ReadonlyMat4 } from 'gl-matrix';
|
|
2
|
+
import Camera from '../../Camera.js';
|
|
3
|
+
import { AbstractSkyEntity } from '../AbstractSkyEntity.js';
|
|
4
|
+
import type { XYZTileCoord, XYZVisibleTileSelection } from './XYZTypes.js';
|
|
12
5
|
export declare class XYZVisibleTilesManager {
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
private buildFallbackSeedTiles;
|
|
26
|
-
private orderTilesByScreenRelevance;
|
|
27
|
-
private orderFallbackTiles;
|
|
28
|
-
private getCenterTileCoord;
|
|
6
|
+
private _ancestorsMap;
|
|
7
|
+
private _visibleTilesMap;
|
|
8
|
+
private _visibleTiles;
|
|
9
|
+
private _selection;
|
|
10
|
+
get ancestorsMap(): Map<string, XYZTileCoord>;
|
|
11
|
+
get visibleTiles(): XYZTileCoord[];
|
|
12
|
+
get visibleTilesMap(): Map<string, XYZTileCoord>;
|
|
13
|
+
get selection(): XYZVisibleTileSelection;
|
|
14
|
+
computeVisibleTiles(z: number, xyzModel: AbstractSkyEntity, webgl: WebGL2RenderingContext, camera: Camera, pMatrix: ReadonlyMat4, sampleCount?: number, padding?: number): XYZVisibleTileSelection;
|
|
15
|
+
private refreshAncestorsMap;
|
|
16
|
+
private buildTileMap;
|
|
17
|
+
private buildSelectionKey;
|
|
29
18
|
private key;
|
|
30
19
|
}
|
|
@@ -1,206 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AstroViewer
|
|
3
|
+
* Copyright (C) Fabrizio Giordano
|
|
4
|
+
* SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
|
|
5
|
+
*
|
|
6
|
+
* This file is part of AstroViewer.
|
|
7
|
+
* AstroViewer is distributed under a dual-license model.
|
|
8
|
+
* Commercial use requires a separate commercial license.
|
|
9
|
+
* Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
|
|
10
|
+
*
|
|
11
|
+
* See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
|
|
12
|
+
*/
|
|
13
|
+
import XYZRayPickingUtils from '../../utils/XYZRayPickingUtils.js';
|
|
1
14
|
export class XYZVisibleTilesManager {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
_ancestorsMap = new Map();
|
|
16
|
+
_visibleTilesMap = new Map();
|
|
17
|
+
_visibleTiles = [];
|
|
18
|
+
_selection = {
|
|
19
|
+
key: '0:',
|
|
20
|
+
currentZoom: 0,
|
|
21
|
+
visibleTiles: [],
|
|
22
|
+
visibleTilesMap: new Map(),
|
|
23
|
+
ancestorsMap: new Map(),
|
|
24
|
+
};
|
|
25
|
+
get ancestorsMap() {
|
|
26
|
+
return this._ancestorsMap;
|
|
27
|
+
}
|
|
28
|
+
get visibleTiles() {
|
|
29
|
+
return this._visibleTiles;
|
|
30
|
+
}
|
|
31
|
+
get visibleTilesMap() {
|
|
32
|
+
return this._visibleTilesMap;
|
|
33
|
+
}
|
|
34
|
+
get selection() {
|
|
35
|
+
return this._selection;
|
|
36
|
+
}
|
|
37
|
+
computeVisibleTiles(z, xyzModel, webgl, camera, pMatrix, sampleCount = 9, padding = 2) {
|
|
38
|
+
this._visibleTiles = XYZRayPickingUtils.getVisibleTilesFromViewport(z, xyzModel, webgl, camera, pMatrix, sampleCount, padding);
|
|
39
|
+
this._visibleTilesMap = this.buildTileMap(this._visibleTiles);
|
|
40
|
+
this.refreshAncestorsMap(this._visibleTiles);
|
|
41
|
+
this._selection = {
|
|
42
|
+
key: this.buildSelectionKey(z, this._visibleTiles),
|
|
43
|
+
currentZoom: z,
|
|
44
|
+
visibleTiles: this._visibleTiles,
|
|
45
|
+
visibleTilesMap: this._visibleTilesMap,
|
|
46
|
+
ancestorsMap: this._ancestorsMap,
|
|
21
47
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
tiles.push(this._provider.tileFromSpherical(currentZoom, sample));
|
|
31
|
-
}
|
|
32
|
-
return this._provider.deduplicateTiles(tiles);
|
|
33
|
-
}
|
|
34
|
-
buildCoverageTiles(currentZoom, input, coreTiles) {
|
|
35
|
-
if (coreTiles.length === 0) {
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
const ring = this.getNeighborRing(currentZoom, input.fovDeg ?? 180);
|
|
39
|
-
if (ring <= 0) {
|
|
40
|
-
return [];
|
|
41
|
-
}
|
|
42
|
-
const coreSet = new Set(coreTiles.map((tile) => this.key(tile)));
|
|
43
|
-
const coverageTiles = [];
|
|
44
|
-
for (const tile of coreTiles) {
|
|
45
|
-
if (!this.isBoundaryTile(tile, coreSet)) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const neighbors = this._provider.getNeighborTiles(tile, ring);
|
|
49
|
-
for (const neighbor of neighbors) {
|
|
50
|
-
const neighborKey = this.key(neighbor);
|
|
51
|
-
if (coreSet.has(neighborKey)) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
coverageTiles.push(neighbor);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return this._provider.deduplicateTiles(coverageTiles);
|
|
58
|
-
}
|
|
59
|
-
collectCoverageSamples(input) {
|
|
60
|
-
const samples = [];
|
|
61
|
-
if (input.centerSphericalDeg) {
|
|
62
|
-
samples.push(input.centerSphericalDeg);
|
|
63
|
-
}
|
|
64
|
-
for (const sample of input.viewportSphericalSamples ?? []) {
|
|
65
|
-
samples.push(sample);
|
|
66
|
-
}
|
|
67
|
-
const polygonSamples = this.interpolateFoVPolygon(input.fovPolygon ?? []);
|
|
68
|
-
for (const sample of polygonSamples) {
|
|
69
|
-
samples.push(sample);
|
|
70
|
-
}
|
|
71
|
-
return samples;
|
|
72
|
-
}
|
|
73
|
-
interpolateFoVPolygon(fovPolygon) {
|
|
74
|
-
if (fovPolygon.length === 0) {
|
|
75
|
-
return [];
|
|
76
|
-
}
|
|
77
|
-
const polygonSpherical = fovPolygon.map((point) => ({
|
|
78
|
-
phi: point.raDeg < 0 ? point.raDeg + 360 : point.raDeg,
|
|
79
|
-
theta: 90 - point.decDeg,
|
|
80
|
-
}));
|
|
81
|
-
const samples = [...polygonSpherical];
|
|
82
|
-
const segmentInterpolationCount = polygonSpherical.length >= 4 ? 3 : 1;
|
|
83
|
-
for (let i = 0; i < polygonSpherical.length; i++) {
|
|
84
|
-
const start = polygonSpherical[i];
|
|
85
|
-
const end = polygonSpherical[(i + 1) % polygonSpherical.length];
|
|
86
|
-
if (!start || !end)
|
|
87
|
-
continue;
|
|
88
|
-
const startPhi = this.normalizePhi(start.phi);
|
|
89
|
-
let endPhi = this.normalizePhi(end.phi);
|
|
90
|
-
if (Math.abs(endPhi - startPhi) > 180) {
|
|
91
|
-
endPhi += endPhi > startPhi ? -360 : 360;
|
|
92
|
-
}
|
|
93
|
-
for (let step = 1; step <= segmentInterpolationCount; step++) {
|
|
94
|
-
const t = step / (segmentInterpolationCount + 1);
|
|
95
|
-
const phi = this.normalizePhi(startPhi + (endPhi - startPhi) * t);
|
|
96
|
-
const theta = start.theta + (end.theta - start.theta) * t;
|
|
97
|
-
samples.push({ phi, theta });
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return samples;
|
|
101
|
-
}
|
|
102
|
-
getNeighborRing(currentZoom, fovDeg) {
|
|
103
|
-
if (currentZoom >= 14 && fovDeg < 10) {
|
|
104
|
-
return 0;
|
|
105
|
-
}
|
|
106
|
-
return 1;
|
|
107
|
-
}
|
|
108
|
-
isBoundaryTile(tile, coreTileKeys) {
|
|
109
|
-
const directNeighbors = [
|
|
110
|
-
{ z: tile.z, x: tile.x - 1, y: tile.y },
|
|
111
|
-
{ z: tile.z, x: tile.x + 1, y: tile.y },
|
|
112
|
-
{ z: tile.z, x: tile.x, y: tile.y - 1 },
|
|
113
|
-
{ z: tile.z, x: tile.x, y: tile.y + 1 },
|
|
114
|
-
];
|
|
115
|
-
return directNeighbors.some((neighbor) => !coreTileKeys.has(this.key(this.normalizeTile(neighbor))));
|
|
116
|
-
}
|
|
117
|
-
normalizeTile(tile) {
|
|
118
|
-
const dim = 2 ** tile.z;
|
|
119
|
-
return {
|
|
120
|
-
z: tile.z,
|
|
121
|
-
x: ((tile.x % dim) + dim) % dim,
|
|
122
|
-
y: Math.max(0, Math.min(dim - 1, tile.y)),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
normalizePhi(phi) {
|
|
126
|
-
let value = phi;
|
|
127
|
-
while (value < 0)
|
|
128
|
-
value += 360;
|
|
129
|
-
while (value >= 360)
|
|
130
|
-
value -= 360;
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
buildFallbackMap(currentTiles, currentZoom) {
|
|
134
|
-
const fallbackMap = new Map();
|
|
135
|
-
const minFallbackZoom = Math.max(this._provider.minZoom, currentZoom - 2);
|
|
136
|
-
for (let z = currentZoom - 1; z >= minFallbackZoom; z--) {
|
|
137
|
-
const dz = currentZoom - z;
|
|
138
|
-
for (const tile of currentTiles) {
|
|
139
|
-
const fallback = {
|
|
48
|
+
return this._selection;
|
|
49
|
+
}
|
|
50
|
+
refreshAncestorsMap(visibleTiles) {
|
|
51
|
+
this._ancestorsMap.clear();
|
|
52
|
+
for (const tile of visibleTiles) {
|
|
53
|
+
for (let z = tile.z - 1; z >= 0; z--) {
|
|
54
|
+
const dz = tile.z - z;
|
|
55
|
+
const ancestor = {
|
|
140
56
|
z,
|
|
141
57
|
x: tile.x >> dz,
|
|
142
58
|
y: tile.y >> dz,
|
|
143
59
|
};
|
|
144
|
-
|
|
60
|
+
this._ancestorsMap.set(`${ancestor.z}/${ancestor.x}/${ancestor.y}`, ancestor);
|
|
145
61
|
}
|
|
146
62
|
}
|
|
147
|
-
return fallbackMap;
|
|
148
63
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const centerTile = this.getCenterTileCoord(zoom, centerSphericalDeg);
|
|
154
|
-
if (!centerTile) {
|
|
155
|
-
return coreTiles;
|
|
64
|
+
buildTileMap(tiles) {
|
|
65
|
+
const map = new Map();
|
|
66
|
+
for (const tile of tiles) {
|
|
67
|
+
map.set(this.key(tile), tile);
|
|
156
68
|
}
|
|
157
|
-
|
|
158
|
-
if (coreTiles.some((tile) => this.key(tile) === centerKey)) {
|
|
159
|
-
return coreTiles;
|
|
160
|
-
}
|
|
161
|
-
return [...coreTiles, centerTile];
|
|
162
|
-
}
|
|
163
|
-
orderTilesByScreenRelevance(tiles, zoom, centerSphericalDeg) {
|
|
164
|
-
const centerTile = this.getCenterTileCoord(zoom, centerSphericalDeg);
|
|
165
|
-
if (!centerTile) {
|
|
166
|
-
return tiles;
|
|
167
|
-
}
|
|
168
|
-
return [...tiles].sort((a, b) => {
|
|
169
|
-
const distanceA = Math.abs(a.x - centerTile.x) + Math.abs(a.y - centerTile.y);
|
|
170
|
-
const distanceB = Math.abs(b.x - centerTile.x) + Math.abs(b.y - centerTile.y);
|
|
171
|
-
return distanceA - distanceB;
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
orderFallbackTiles(tiles, currentZoom, centerSphericalDeg) {
|
|
175
|
-
return [...tiles].sort((a, b) => {
|
|
176
|
-
if (b.z !== a.z) {
|
|
177
|
-
return b.z - a.z;
|
|
178
|
-
}
|
|
179
|
-
const centerTileA = this.getCenterTileCoord(a.z, centerSphericalDeg);
|
|
180
|
-
const centerTileB = this.getCenterTileCoord(b.z, centerSphericalDeg);
|
|
181
|
-
if (!centerTileA || !centerTileB) {
|
|
182
|
-
return 0;
|
|
183
|
-
}
|
|
184
|
-
const distanceA = Math.abs(a.x - centerTileA.x) + Math.abs(a.y - centerTileA.y);
|
|
185
|
-
const distanceB = Math.abs(b.x - centerTileB.x) + Math.abs(b.y - centerTileB.y);
|
|
186
|
-
return distanceA - distanceB || currentZoom - a.z - (currentZoom - b.z);
|
|
187
|
-
});
|
|
69
|
+
return map;
|
|
188
70
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
const lonDeg = centerSphericalDeg.phi > 180 ? centerSphericalDeg.phi - 360 : centerSphericalDeg.phi;
|
|
194
|
-
const latDeg = 90 - centerSphericalDeg.theta;
|
|
195
|
-
const dim = 2 ** zoom;
|
|
196
|
-
const x = Math.floor(((lonDeg + 180) / 360) * dim);
|
|
197
|
-
const latRad = (Math.max(-85.0511287798066, Math.min(85.0511287798066, latDeg)) * Math.PI) / 180;
|
|
198
|
-
const y = Math.floor(((1 - Math.asinh(Math.tan(latRad)) / Math.PI) / 2) * dim);
|
|
199
|
-
return {
|
|
200
|
-
z: zoom,
|
|
201
|
-
x: ((x % dim) + dim) % dim,
|
|
202
|
-
y: Math.max(0, Math.min(dim - 1, y)),
|
|
203
|
-
};
|
|
71
|
+
buildSelectionKey(z, tiles) {
|
|
72
|
+
return `${z}:${tiles.map((tile) => `${tile.x}/${tile.y}`).join('|')}`;
|
|
204
73
|
}
|
|
205
74
|
key(tile) {
|
|
206
75
|
return `${tile.z}/${tile.x}/${tile.y}`;
|