astro-viewer 2.0.0 → 3.1.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 +19832 -16986
- package/dist/astroviewer.js +1 -1
- package/dist/astroviewer.min.js +1 -1
- package/lib-esm/AstroSphere.d.ts +31 -2
- package/lib-esm/AstroSphere.js +267 -16
- package/lib-esm/AstroViewer.d.ts +33 -2
- package/lib-esm/AstroViewer.js +93 -0
- package/lib-esm/Camera.js +24 -8
- package/lib-esm/Config.js +12 -0
- package/lib-esm/Global.js +12 -0
- package/lib-esm/index.d.ts +8 -1
- package/lib-esm/index.js +18 -1
- package/lib-esm/model/AbstractSkyEntity.d.ts +10 -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.js +12 -0
- package/lib-esm/model/Point.js +12 -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 +195 -0
- package/lib-esm/model/catalogues/CatalogueGL.js +12 -0
- package/lib-esm/model/catalogues/CatalogueProps.js +13 -1
- package/lib-esm/model/earth/WMTSAdapter.d.ts +12 -0
- package/lib-esm/model/earth/WMTSAdapter.js +97 -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/XYZConfig.d.ts +72 -0
- package/lib-esm/model/earth/XYZConfig.js +13 -0
- package/lib-esm/model/earth/XYZFoVHelper.d.ts +9 -0
- package/lib-esm/model/earth/XYZFoVHelper.js +101 -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 +6 -0
- package/lib-esm/model/earth/XYZMeshBuilder.js +108 -0
- package/lib-esm/model/earth/XYZTile.d.ts +38 -0
- package/lib-esm/model/earth/XYZTile.js +167 -0
- package/lib-esm/model/earth/XYZTileBuffer.d.ts +37 -0
- package/lib-esm/model/earth/XYZTileBuffer.js +139 -0
- package/lib-esm/model/earth/XYZTileRequestScheduler.d.ts +25 -0
- package/lib-esm/model/earth/XYZTileRequestScheduler.js +172 -0
- 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 +19 -0
- package/lib-esm/model/earth/XYZVisibleTilesManager.js +77 -0
- package/lib-esm/model/footprints/Footprint.js +12 -0
- package/lib-esm/model/footprints/FootprintProps.js +13 -1
- package/lib-esm/model/footprints/FootprintSetGL.js +13 -1
- package/lib-esm/model/grid/EquatorialGrid.js +20 -6
- 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 +19 -6
- package/lib-esm/model/grid/LonLatGrid.d.ts +40 -0
- package/lib-esm/model/grid/LonLatGrid.js +258 -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.js +12 -0
- package/lib-esm/model/hips/HiPS.js +12 -9
- package/lib-esm/model/hips/HiPSDescriptor.js +12 -0
- package/lib-esm/model/hips/Tile.js +12 -0
- package/lib-esm/model/hips/TileBuffer.js +12 -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 +4 -0
- package/lib-esm/model/terra/TerraFootprintSetGL.js +16 -0
- package/lib-esm/model/terra/TerraPointSetGL.d.ts +4 -0
- package/lib-esm/model/terra/TerraPointSetGL.js +16 -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 +33 -0
- package/lib-esm/shader/XYZShaderProgram.js +213 -0
- package/lib-esm/utils/CoordsType.js +12 -0
- package/lib-esm/utils/FoVUtils.js +12 -0
- package/lib-esm/utils/GeomUtils.js +12 -0
- package/lib-esm/utils/MouseHelper.js +12 -0
- package/lib-esm/utils/PerspectiveMatrixManager.js +12 -0
- package/lib-esm/utils/RayPickingUtils.js +12 -0
- package/lib-esm/utils/STCSParser.js +12 -0
- 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 +1 -2
- package/lib-esm/model/FoV.d.ts +0 -62
- package/lib-esm/model/FoV.js +0 -274
|
@@ -0,0 +1,172 @@
|
|
|
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 class XYZTileRequestError extends Error {
|
|
14
|
+
cooldownMs;
|
|
15
|
+
retryable;
|
|
16
|
+
constructor(message, cooldownMs, retryable = true) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'XYZTileRequestError';
|
|
19
|
+
this.cooldownMs = cooldownMs;
|
|
20
|
+
this.retryable = retryable;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class XYZTileRequestScheduler {
|
|
24
|
+
_maxConcurrent;
|
|
25
|
+
_activeCount = 0;
|
|
26
|
+
_queue = [];
|
|
27
|
+
_inflight = new Map();
|
|
28
|
+
_hostBackoff = new Map();
|
|
29
|
+
_sequence = 0;
|
|
30
|
+
constructor(maxConcurrent = 4) {
|
|
31
|
+
this._maxConcurrent = maxConcurrent;
|
|
32
|
+
}
|
|
33
|
+
setMaxConcurrent(maxConcurrent) {
|
|
34
|
+
this._maxConcurrent = Math.max(1, Math.floor(maxConcurrent));
|
|
35
|
+
this.pump();
|
|
36
|
+
}
|
|
37
|
+
getMaxConcurrent() {
|
|
38
|
+
return this._maxConcurrent;
|
|
39
|
+
}
|
|
40
|
+
getDebugStats() {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const hostsInBackoff = Array.from(this._hostBackoff.entries())
|
|
43
|
+
.map(([host, state]) => ({
|
|
44
|
+
host,
|
|
45
|
+
cooldownMs: Math.max(0, state.cooldownUntil - now),
|
|
46
|
+
consecutiveFailures: state.consecutiveFailures,
|
|
47
|
+
}))
|
|
48
|
+
.filter((entry) => entry.cooldownMs > 0 || entry.consecutiveFailures > 0)
|
|
49
|
+
.sort((a, b) => b.cooldownMs - a.cooldownMs);
|
|
50
|
+
return {
|
|
51
|
+
activeRequests: this._activeCount,
|
|
52
|
+
queuedRequests: this._queue.length,
|
|
53
|
+
inflightRequests: this._inflight.size,
|
|
54
|
+
maxConcurrentRequests: this._maxConcurrent,
|
|
55
|
+
highestQueuedPriority: this._queue[0]?.priority ?? null,
|
|
56
|
+
hostsInBackoff,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
load(url, priority = 0) {
|
|
60
|
+
const inflight = this._inflight.get(url);
|
|
61
|
+
if (inflight) {
|
|
62
|
+
return inflight;
|
|
63
|
+
}
|
|
64
|
+
const hostCooldown = this.getHostCooldown(url);
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
if (hostCooldown > now) {
|
|
67
|
+
return Promise.reject(new XYZTileRequestError(`Cooldown active for ${new URL(url).host}`, hostCooldown - now));
|
|
68
|
+
}
|
|
69
|
+
const promise = new Promise((resolve, reject) => {
|
|
70
|
+
this._queue.push({
|
|
71
|
+
url,
|
|
72
|
+
resolve,
|
|
73
|
+
reject,
|
|
74
|
+
priority,
|
|
75
|
+
sequence: this._sequence++,
|
|
76
|
+
});
|
|
77
|
+
this._queue.sort((a, b) => b.priority - a.priority || a.sequence - b.sequence);
|
|
78
|
+
this.pump();
|
|
79
|
+
}).finally(() => {
|
|
80
|
+
this._inflight.delete(url);
|
|
81
|
+
});
|
|
82
|
+
this._inflight.set(url, promise);
|
|
83
|
+
return promise;
|
|
84
|
+
}
|
|
85
|
+
pump() {
|
|
86
|
+
while (this._activeCount < this._maxConcurrent && this._queue.length > 0) {
|
|
87
|
+
const item = this._queue.shift();
|
|
88
|
+
if (!item)
|
|
89
|
+
return;
|
|
90
|
+
const hostCooldown = this.getHostCooldown(item.url);
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
if (hostCooldown > now) {
|
|
93
|
+
item.reject(new XYZTileRequestError(`Cooldown active for ${new URL(item.url).host}`, hostCooldown - now));
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
this._activeCount += 1;
|
|
97
|
+
this.fetchBlob(item)
|
|
98
|
+
.then(item.resolve)
|
|
99
|
+
.catch(item.reject)
|
|
100
|
+
.finally(() => {
|
|
101
|
+
this._activeCount -= 1;
|
|
102
|
+
this.pump();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async fetchBlob(item) {
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(item.url, {
|
|
109
|
+
mode: 'cors',
|
|
110
|
+
cache: 'force-cache',
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
const isTransient = response.status === 429 || response.status >= 500;
|
|
114
|
+
const cooldownMs = this.registerFailure(item.url, isTransient);
|
|
115
|
+
throw new XYZTileRequestError(`HTTP ${response.status} loading ${item.url}`, isTransient ? cooldownMs : 5 * 60 * 1000, isTransient);
|
|
116
|
+
}
|
|
117
|
+
this.registerSuccess(item.url);
|
|
118
|
+
return await response.blob();
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error instanceof XYZTileRequestError) {
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
const cooldownMs = this.registerFailure(item.url, false);
|
|
125
|
+
throw new XYZTileRequestError(`Network/CORS failure loading ${item.url}`, cooldownMs, true);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
getHostCooldown(url) {
|
|
129
|
+
try {
|
|
130
|
+
return this._hostBackoff.get(new URL(url).host)?.cooldownUntil ?? 0;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
registerSuccess(url) {
|
|
137
|
+
try {
|
|
138
|
+
const host = new URL(url).host;
|
|
139
|
+
this._hostBackoff.set(host, {
|
|
140
|
+
cooldownUntil: 0,
|
|
141
|
+
consecutiveFailures: 0,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// no-op
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
registerFailure(url, isRateLimited) {
|
|
149
|
+
if (!isRateLimited) {
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const host = new URL(url).host;
|
|
154
|
+
const previous = this._hostBackoff.get(host) ?? {
|
|
155
|
+
cooldownUntil: 0,
|
|
156
|
+
consecutiveFailures: 0,
|
|
157
|
+
};
|
|
158
|
+
const consecutiveFailures = previous.consecutiveFailures + 1;
|
|
159
|
+
const baseDelayMs = 4000;
|
|
160
|
+
const cooldownMs = Math.min(120000, baseDelayMs * (2 ** Math.min(consecutiveFailures - 1, 5)));
|
|
161
|
+
this._hostBackoff.set(host, {
|
|
162
|
+
cooldownUntil: Date.now() + cooldownMs,
|
|
163
|
+
consecutiveFailures,
|
|
164
|
+
});
|
|
165
|
+
return cooldownMs;
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return 30000;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
export const xyzTileRequestScheduler = new XYZTileRequestScheduler();
|
|
@@ -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 {};
|
|
@@ -0,0 +1,19 @@
|
|
|
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';
|
|
5
|
+
export declare class XYZVisibleTilesManager {
|
|
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;
|
|
18
|
+
private key;
|
|
19
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
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';
|
|
14
|
+
export class XYZVisibleTilesManager {
|
|
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,
|
|
47
|
+
};
|
|
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 = {
|
|
56
|
+
z,
|
|
57
|
+
x: tile.x >> dz,
|
|
58
|
+
y: tile.y >> dz,
|
|
59
|
+
};
|
|
60
|
+
this._ancestorsMap.set(`${ancestor.z}/${ancestor.x}/${ancestor.y}`, ancestor);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
buildTileMap(tiles) {
|
|
65
|
+
const map = new Map();
|
|
66
|
+
for (const tile of tiles) {
|
|
67
|
+
map.set(this.key(tile), tile);
|
|
68
|
+
}
|
|
69
|
+
return map;
|
|
70
|
+
}
|
|
71
|
+
buildSelectionKey(z, tiles) {
|
|
72
|
+
return `${z}:${tiles.map((tile) => `${tile.x}/${tile.y}`).join('|')}`;
|
|
73
|
+
}
|
|
74
|
+
key(tile) {
|
|
75
|
+
return `${tile.z}/${tile.x}/${tile.y}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -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
|
'use strict';
|
|
2
14
|
/**
|
|
3
15
|
* @author Fabrizio Giordano (Fab)
|
|
@@ -1,6 +1,18 @@
|
|
|
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
14
|
// import {Metadata} from '../tap/TapMetadata.js';
|
|
2
15
|
// import {TapMetadataList} from '../tap/TapMetadataList.js';
|
|
3
|
-
export {};
|
|
4
16
|
// export default class FootprintProps {
|
|
5
17
|
// // resolved columns
|
|
6
18
|
// pgSphereColumn?: Metadata;
|
|
@@ -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
|
import { Footprint } from "./Footprint.js";
|
|
2
14
|
import { colorHex2RGB } from "../../utils/Utils.js";
|
|
3
15
|
import { FootprintShaderProgram } from "../../shader/FootprintShaderProgram.js";
|
|
@@ -126,7 +138,7 @@ export class FootprintSetGL {
|
|
|
126
138
|
throw new Error("geomColumn or its index is undefined in footprintsetProps");
|
|
127
139
|
}
|
|
128
140
|
for (let j = 0; j < in_data.length; j++) {
|
|
129
|
-
if (in_data[j][
|
|
141
|
+
if (in_data[j][geomDataIndex] !== null) {
|
|
130
142
|
const footprint = new Footprint(in_data[j][geomDataIndex], in_data[j]);
|
|
131
143
|
if (footprint._valid) {
|
|
132
144
|
this.addFootprint(footprint);
|
|
@@ -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
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
14
|
import { vec4, mat4 } from 'gl-matrix';
|
|
3
15
|
import { fovHelper } from '../hips/FoVHelper.js';
|
|
@@ -19,7 +31,7 @@ export class EquatorialGrid extends AbstractSkyEntity {
|
|
|
19
31
|
_vertexShader;
|
|
20
32
|
_fragmentShader;
|
|
21
33
|
defaultColor = '#41d421';
|
|
22
|
-
gridText = new GridTextHelper();
|
|
34
|
+
gridText = new GridTextHelper('equatorial');
|
|
23
35
|
_attribLocations = {
|
|
24
36
|
position: 0,
|
|
25
37
|
selected: 1,
|
|
@@ -260,9 +272,10 @@ export class EquatorialGrid extends AbstractSkyEntity {
|
|
|
260
272
|
// perspective divide
|
|
261
273
|
clipspace[0] /= clipspace[3];
|
|
262
274
|
clipspace[1] /= clipspace[3];
|
|
263
|
-
// clip->
|
|
264
|
-
const
|
|
265
|
-
const
|
|
275
|
+
// clip -> CSS pixels
|
|
276
|
+
const canvasRect = super.webgl.canvas.getBoundingClientRect();
|
|
277
|
+
const pixelX = canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width;
|
|
278
|
+
const pixelY = canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height;
|
|
266
279
|
this.gridText.addEqDivSet(decDeg.toFixed(2), pixelX, pixelY, 'dec');
|
|
267
280
|
// gridTextHelper.addEqDivSet(decDeg.toFixed(2), pixelX, pixelY, 'dec');
|
|
268
281
|
}
|
|
@@ -283,8 +296,9 @@ export class EquatorialGrid extends AbstractSkyEntity {
|
|
|
283
296
|
vec4.transformMat4(clipspace, phiPoint, mvpMatrix);
|
|
284
297
|
clipspace[0] /= clipspace[3];
|
|
285
298
|
clipspace[1] /= clipspace[3];
|
|
286
|
-
const
|
|
287
|
-
const
|
|
299
|
+
const canvasRect = super.webgl.canvas.getBoundingClientRect();
|
|
300
|
+
const pixelX = canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width;
|
|
301
|
+
const pixelY = canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height;
|
|
288
302
|
// gridTextHelper.addEqDivSet(raDeg.toFixed(2), pixelX, pixelY, 'ra');
|
|
289
303
|
this.gridText.addEqDivSet(raDeg.toFixed(2), pixelX, pixelY, 'ra');
|
|
290
304
|
}
|
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
* @author Fabrizio Giordano (Fab)
|
|
3
|
-
* @param in_radius - number
|
|
4
|
-
* @param in_gl - GL context
|
|
5
|
-
* @param in_position - array of double e.g. [0.0, 0.0, 0.0]
|
|
6
|
-
*/
|
|
1
|
+
type GridLabelLayer = 'healpix' | 'equatorial' | 'lonlat';
|
|
7
2
|
declare class GridTextHelper {
|
|
8
|
-
private
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
private _divSetNdx;
|
|
12
|
-
constructor();
|
|
3
|
+
private static layers;
|
|
4
|
+
private layer;
|
|
5
|
+
constructor(layer?: GridLabelLayer);
|
|
13
6
|
initHtml(): void;
|
|
14
|
-
resetDivSets(): void;
|
|
15
|
-
/**
|
|
16
|
-
* Add / reuse a floating label for HPX coordinates
|
|
17
|
-
*/
|
|
7
|
+
resetDivSets(layer?: GridLabelLayer): void;
|
|
18
8
|
addHPXDivSet(msg: string, x: number, y: number): void;
|
|
19
|
-
/**
|
|
20
|
-
* Add / reuse a floating label for Equatorial coords
|
|
21
|
-
* @param type 'ra' or 'dec'
|
|
22
|
-
*/
|
|
23
9
|
addEqDivSet(msg: string, x: number, y: number, type: 'ra' | 'dec'): void;
|
|
10
|
+
addLonLatDivSet(msg: string, x: number, y: number, type: 'lon' | 'lat'): void;
|
|
11
|
+
private addLabel;
|
|
12
|
+
private classNameForKind;
|
|
13
|
+
private static getLayerState;
|
|
14
|
+
private static resolveContainer;
|
|
24
15
|
}
|
|
25
16
|
export default GridTextHelper;
|
|
@@ -1,91 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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.
|
|
6
12
|
*/
|
|
7
13
|
class GridTextHelper {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this._divEqContainerElement = document.querySelector('#gridcoords');
|
|
14
|
-
this._divHPXContainerElement = document.querySelector('#gridhpx');
|
|
15
|
-
this._divSetNdx = 0;
|
|
16
|
-
this._divSets = [];
|
|
14
|
+
static layers = new Map();
|
|
15
|
+
layer;
|
|
16
|
+
constructor(layer = 'equatorial') {
|
|
17
|
+
this.layer = layer;
|
|
18
|
+
GridTextHelper.getLayerState(layer);
|
|
17
19
|
}
|
|
18
20
|
initHtml() {
|
|
19
|
-
|
|
21
|
+
GridTextHelper.getLayerState(this.layer);
|
|
20
22
|
}
|
|
21
|
-
resetDivSets() {
|
|
22
|
-
|
|
23
|
-
for (;
|
|
24
|
-
|
|
23
|
+
resetDivSets(layer = this.layer) {
|
|
24
|
+
const state = GridTextHelper.getLayerState(layer);
|
|
25
|
+
for (; state.divSetNdx < state.divSets.length; ++state.divSetNdx) {
|
|
26
|
+
state.divSets[state.divSetNdx].style.display = 'none';
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
state.divSetNdx = 0;
|
|
27
29
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Add / reuse a floating label for HPX coordinates
|
|
30
|
-
*/
|
|
31
30
|
addHPXDivSet(msg, x, y) {
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
this.addLabel('healpix', msg, x + 25, y, 'hpx');
|
|
32
|
+
}
|
|
33
|
+
addEqDivSet(msg, x, y, type) {
|
|
34
|
+
this.addLabel('equatorial', msg, type === 'ra' ? x + 25 : x, type === 'ra' ? y : y + 25, type);
|
|
35
|
+
}
|
|
36
|
+
addLonLatDivSet(msg, x, y, type) {
|
|
37
|
+
this.addLabel('lonlat', msg, type === 'lon' ? x + 25 : x, type === 'lon' ? y : y + 25, type);
|
|
38
|
+
}
|
|
39
|
+
addLabel(layer, msg, x, y, kind) {
|
|
40
|
+
const state = GridTextHelper.getLayerState(layer);
|
|
41
|
+
if (!state.container)
|
|
42
|
+
return;
|
|
43
|
+
let divSet = state.divSets[state.divSetNdx++];
|
|
34
44
|
if (!divSet) {
|
|
35
45
|
const div = document.createElement('div');
|
|
36
46
|
const textNode = document.createTextNode('');
|
|
37
|
-
div.className = 'floating-div-ra'; // style like RA tags
|
|
38
47
|
div.appendChild(textNode);
|
|
39
|
-
|
|
40
|
-
this._divHPXContainerElement = document.querySelector('#gridhpx');
|
|
41
|
-
}
|
|
42
|
-
if (!this._divHPXContainerElement) {
|
|
43
|
-
// If container is still missing, abort gracefully
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
this._divHPXContainerElement.appendChild(div);
|
|
48
|
+
state.container.appendChild(div);
|
|
47
49
|
divSet = { div, textNode, style: div.style };
|
|
48
|
-
|
|
50
|
+
state.divSets.push(divSet);
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
divSet.div.className = this.classNameForKind(kind);
|
|
51
53
|
divSet.style.display = 'block';
|
|
52
|
-
divSet.style.left = `${Math.floor(x
|
|
54
|
+
divSet.style.left = `${Math.floor(x)}px`;
|
|
53
55
|
divSet.style.top = `${Math.floor(y)}px`;
|
|
54
56
|
divSet.textNode.nodeValue = msg;
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this._divEqContainerElement = document.querySelector('#gridcoords');
|
|
69
|
-
}
|
|
70
|
-
if (!this._divEqContainerElement) {
|
|
71
|
-
// If container is still missing, abort gracefully
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
this._divEqContainerElement.appendChild(div);
|
|
75
|
-
divSet = { div, textNode, style: div.style };
|
|
76
|
-
this._divSets.push(divSet);
|
|
58
|
+
classNameForKind(kind) {
|
|
59
|
+
switch (kind) {
|
|
60
|
+
case 'dec':
|
|
61
|
+
return 'floating-div-dec';
|
|
62
|
+
case 'lat':
|
|
63
|
+
return 'floating-div-lat';
|
|
64
|
+
case 'lon':
|
|
65
|
+
return 'floating-div-lon';
|
|
66
|
+
case 'hpx':
|
|
67
|
+
case 'ra':
|
|
68
|
+
default:
|
|
69
|
+
return 'floating-div-ra';
|
|
77
70
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
}
|
|
72
|
+
static getLayerState(layer) {
|
|
73
|
+
const current = GridTextHelper.layers.get(layer);
|
|
74
|
+
if (current) {
|
|
75
|
+
if (!current.container)
|
|
76
|
+
current.container = GridTextHelper.resolveContainer(layer);
|
|
77
|
+
return current;
|
|
82
78
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
const state = {
|
|
80
|
+
container: GridTextHelper.resolveContainer(layer),
|
|
81
|
+
divSets: [],
|
|
82
|
+
divSetNdx: 0,
|
|
83
|
+
};
|
|
84
|
+
GridTextHelper.layers.set(layer, state);
|
|
85
|
+
return state;
|
|
86
|
+
}
|
|
87
|
+
static resolveContainer(layer) {
|
|
88
|
+
if (layer === 'healpix') {
|
|
89
|
+
return document.querySelector('#gridhpx');
|
|
86
90
|
}
|
|
87
|
-
|
|
91
|
+
return document.querySelector('#gridcoords');
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
|
-
// export const gridTextHelper = new GridTextHelper();
|
|
91
94
|
export default GridTextHelper;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbstractSkyEntity, SkyEntityDrawInput } from '../AbstractSkyEntity.js';
|
|
2
2
|
import { ReadonlyMat4 } from 'gl-matrix';
|
|
3
|
-
import {
|
|
3
|
+
import { SphereFoV } from '../SphereFoV.js';
|
|
4
4
|
import { VisibleTilesManager } from '../hips/VisibleTilesManager.js';
|
|
5
5
|
import Camera from '../../Camera.js';
|
|
6
6
|
export declare class HealpixGrid extends AbstractSkyEntity {
|
|
@@ -28,13 +28,13 @@ export declare class HealpixGrid extends AbstractSkyEntity {
|
|
|
28
28
|
private _visibleTilesManager;
|
|
29
29
|
constructor(webgl: WebGL2RenderingContext);
|
|
30
30
|
init(): void;
|
|
31
|
-
get fovObj():
|
|
31
|
+
get fovObj(): SphereFoV;
|
|
32
32
|
get RADIUS(): number;
|
|
33
33
|
get INITIAL_POSITION(): [number, number, number];
|
|
34
34
|
get INITIAL_PhiRad(): number;
|
|
35
35
|
get INITIAL_ThetaRad(): number;
|
|
36
|
-
refreshFoV(camera: Camera, pMatrix: ReadonlyMat4):
|
|
37
|
-
getFoV():
|
|
36
|
+
refreshFoV(camera: Camera, pMatrix: ReadonlyMat4): SphereFoV;
|
|
37
|
+
getFoV(): SphereFoV;
|
|
38
38
|
getMinFoV(): number;
|
|
39
39
|
private initShaders;
|
|
40
40
|
initBuffers(pixels: number[], order: number): void;
|