astro-viewer 3.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.
Files changed (110) hide show
  1. package/dist/astroviewer.cjs +2505 -1335
  2. package/dist/astroviewer.js +1 -1
  3. package/dist/astroviewer.min.js +1 -1
  4. package/lib-esm/AstroSphere.d.ts +26 -6
  5. package/lib-esm/AstroSphere.js +215 -18
  6. package/lib-esm/AstroViewer.d.ts +18 -5
  7. package/lib-esm/AstroViewer.js +47 -0
  8. package/lib-esm/Camera.js +24 -8
  9. package/lib-esm/Config.js +12 -0
  10. package/lib-esm/Global.js +12 -0
  11. package/lib-esm/index.d.ts +6 -4
  12. package/lib-esm/index.js +16 -3
  13. package/lib-esm/model/AbstractSkyEntity.js +12 -0
  14. package/lib-esm/model/AstroGL.js +12 -0
  15. package/lib-esm/model/ColorMaps.js +12 -0
  16. package/lib-esm/model/MetadataColumn.js +12 -0
  17. package/lib-esm/model/MetadataManager.js +12 -0
  18. package/lib-esm/model/Point.js +12 -0
  19. package/lib-esm/model/Point2D.js +12 -0
  20. package/lib-esm/model/Source.js +12 -0
  21. package/lib-esm/model/SphereFoV.d.ts +30 -0
  22. package/lib-esm/model/SphereFoV.js +195 -0
  23. package/lib-esm/model/catalogues/CatalogueGL.js +12 -0
  24. package/lib-esm/model/catalogues/CatalogueProps.js +13 -1
  25. package/lib-esm/model/earth/{wmts/WMTSAdapter.d.ts → WMTSAdapter.d.ts} +2 -1
  26. package/lib-esm/model/earth/{wmts/WMTSAdapter.js → WMTSAdapter.js} +12 -0
  27. package/lib-esm/model/earth/XYZAnchestorTile.d.ts +17 -0
  28. package/lib-esm/model/earth/XYZAnchestorTile.js +87 -0
  29. package/lib-esm/model/earth/{types.d.ts → XYZConfig.d.ts} +2 -17
  30. package/lib-esm/model/earth/XYZConfig.js +13 -0
  31. package/lib-esm/model/earth/XYZFoVHelper.d.ts +9 -0
  32. package/lib-esm/model/earth/XYZFoVHelper.js +101 -0
  33. package/lib-esm/model/earth/XYZMap.d.ts +31 -0
  34. package/lib-esm/model/earth/XYZMap.js +208 -0
  35. package/lib-esm/model/earth/XYZMapDescriptor.d.ts +29 -0
  36. package/lib-esm/model/earth/XYZMapDescriptor.js +77 -0
  37. package/lib-esm/model/earth/XYZMeshBuilder.d.ts +1 -1
  38. package/lib-esm/model/earth/XYZMeshBuilder.js +13 -2
  39. package/lib-esm/model/earth/XYZTile.d.ts +20 -21
  40. package/lib-esm/model/earth/XYZTile.js +82 -102
  41. package/lib-esm/model/earth/XYZTileBuffer.d.ts +24 -26
  42. package/lib-esm/model/earth/XYZTileBuffer.js +60 -70
  43. package/lib-esm/model/earth/XYZTileRequestScheduler.d.ts +1 -1
  44. package/lib-esm/model/earth/XYZTileRequestScheduler.js +13 -2
  45. package/lib-esm/model/earth/XYZTypes.d.ts +24 -0
  46. package/lib-esm/model/earth/XYZTypes.js +13 -0
  47. package/lib-esm/model/earth/XYZVisibleTilesManager.d.ts +16 -27
  48. package/lib-esm/model/earth/XYZVisibleTilesManager.js +61 -192
  49. package/lib-esm/model/footprints/Footprint.js +12 -0
  50. package/lib-esm/model/footprints/FootprintProps.js +13 -1
  51. package/lib-esm/model/footprints/FootprintSetGL.js +12 -0
  52. package/lib-esm/model/grid/EquatorialGrid.js +20 -6
  53. package/lib-esm/model/grid/GridTextHelper.d.ts +10 -19
  54. package/lib-esm/model/grid/GridTextHelper.js +70 -67
  55. package/lib-esm/model/grid/HealpixGrid.d.ts +4 -4
  56. package/lib-esm/model/grid/HealpixGrid.js +19 -6
  57. package/lib-esm/model/grid/LonLatGrid.d.ts +40 -0
  58. package/lib-esm/model/grid/LonLatGrid.js +258 -0
  59. package/lib-esm/model/hips/AllSky.js +12 -0
  60. package/lib-esm/model/hips/AncestorTile.js +12 -0
  61. package/lib-esm/model/hips/FoVHelper.js +12 -0
  62. package/lib-esm/model/hips/HiPS.js +12 -9
  63. package/lib-esm/model/hips/HiPSDescriptor.js +12 -0
  64. package/lib-esm/model/hips/Tile.js +12 -0
  65. package/lib-esm/model/hips/TileBuffer.js +12 -0
  66. package/lib-esm/model/hips/VisibleTilesManager.js +12 -0
  67. package/lib-esm/model/tap/TapMetadata.js +12 -0
  68. package/lib-esm/model/tap/TapMetadataList.js +12 -0
  69. package/lib-esm/model/tap/TapRepo.js +12 -0
  70. package/lib-esm/model/terra/TerraFootprintSetGL.js +12 -0
  71. package/lib-esm/model/terra/TerraPointSetGL.js +12 -0
  72. package/lib-esm/services/SesameService.js +11 -3
  73. package/lib-esm/services/helpers.js +12 -0
  74. package/lib-esm/services/hipsNodeService.js +12 -0
  75. package/lib-esm/services/parse-hipslist.js +12 -0
  76. package/lib-esm/services/queryCatalogueByFoV.js +13 -1
  77. package/lib-esm/services/queryFootprintSetByFov.js +13 -1
  78. package/lib-esm/services/tapRepoService.js +13 -1
  79. package/lib-esm/services/types.js +12 -0
  80. package/lib-esm/shader/CatalogueShaderProgram.js +12 -0
  81. package/lib-esm/shader/FootprintShaderProgram.js +12 -0
  82. package/lib-esm/shader/GridShaderManager.js +12 -0
  83. package/lib-esm/shader/HiPSShaderProgram.js +12 -0
  84. package/lib-esm/shader/ShaderManager.js +12 -1
  85. package/lib-esm/shader/ShaderManagerMutliHiPS.js +12 -1
  86. package/lib-esm/shader/XYZShaderProgram.d.ts +14 -1
  87. package/lib-esm/shader/XYZShaderProgram.js +127 -2
  88. package/lib-esm/utils/CoordsType.js +12 -0
  89. package/lib-esm/utils/FoVUtils.js +12 -0
  90. package/lib-esm/utils/GeomUtils.js +12 -0
  91. package/lib-esm/utils/MouseHelper.js +12 -0
  92. package/lib-esm/utils/PerspectiveMatrixManager.js +12 -0
  93. package/lib-esm/utils/RayPickingUtils.js +12 -0
  94. package/lib-esm/utils/STCSParser.js +12 -0
  95. package/lib-esm/utils/ShaderUtility.js +13 -1
  96. package/lib-esm/utils/Utils.js +12 -0
  97. package/lib-esm/utils/XYZRayPickingUtils.d.ts +27 -0
  98. package/lib-esm/utils/XYZRayPickingUtils.js +226 -0
  99. package/package.json +1 -1
  100. package/lib-esm/model/FoV.d.ts +0 -62
  101. package/lib-esm/model/FoV.js +0 -274
  102. package/lib-esm/model/earth/XYZAncestorMeshCache.d.ts +0 -10
  103. package/lib-esm/model/earth/XYZAncestorMeshCache.js +0 -31
  104. package/lib-esm/model/earth/XYZLayer.d.ts +0 -31
  105. package/lib-esm/model/earth/XYZLayer.js +0 -231
  106. package/lib-esm/model/earth/XYZTileProvider.d.ts +0 -29
  107. package/lib-esm/model/earth/XYZTileProvider.js +0 -187
  108. package/lib-esm/model/earth/types.js +0 -1
  109. package/lib-esm/model/earth/wmts/types.d.ts +0 -1
  110. package/lib-esm/model/earth/wmts/types.js +0 -1
@@ -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
- _provider;
3
- constructor(provider) {
4
- this._provider = provider;
5
- }
6
- selectTiles(input) {
7
- const currentZoom = this._provider.resolveZoom(input.fovDeg ?? 180);
8
- const coreTiles = this.orderTilesByScreenRelevance(this.buildCoreVisibleTiles(currentZoom, input), currentZoom, input.centerSphericalDeg ?? null);
9
- const coverageTiles = this.orderTilesByScreenRelevance(this.buildCoverageTiles(currentZoom, input, coreTiles), currentZoom, input.centerSphericalDeg ?? null);
10
- const currentTiles = [...coreTiles, ...coverageTiles];
11
- const fallbackSeedTiles = this.buildFallbackSeedTiles(coreTiles, currentZoom, input.centerSphericalDeg ?? null);
12
- const fallbackTiles = this.orderFallbackTiles(Array.from(this.buildFallbackMap(fallbackSeedTiles, currentZoom).values()), currentZoom, input.centerSphericalDeg ?? null);
13
- const key = `${currentZoom}:${currentTiles.map((tile) => `${tile.x}/${tile.y}`).join('|')}`;
14
- return {
15
- key,
16
- currentTiles,
17
- fallbackTiles,
18
- currentZoom,
19
- coreTileCount: coreTiles.length,
20
- coverageTileCount: coverageTiles.length,
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
- buildCoreVisibleTiles(currentZoom, input) {
24
- const samples = this.collectCoverageSamples(input);
25
- if (samples.length === 0) {
26
- return this._provider.getVisibleTilesAtZoom(currentZoom, null, [], [], 0);
27
- }
28
- const tiles = [];
29
- for (const sample of samples) {
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
- fallbackMap.set(`${fallback.z}/${fallback.x}/${fallback.y}`, fallback);
60
+ this._ancestorsMap.set(`${ancestor.z}/${ancestor.x}/${ancestor.y}`, ancestor);
145
61
  }
146
62
  }
147
- return fallbackMap;
148
63
  }
149
- buildFallbackSeedTiles(coreTiles, zoom, centerSphericalDeg) {
150
- if (coreTiles.length === 0) {
151
- return [];
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
- const centerKey = this.key(centerTile);
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
- getCenterTileCoord(zoom, centerSphericalDeg) {
190
- if (!centerSphericalDeg) {
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}`;
@@ -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";
@@ -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->pixel
264
- const pixelX = (clipspace[0] * 0.5 + 0.5) * super.webgl.canvas.width;
265
- const pixelY = (clipspace[1] * -0.5 + 0.5) * super.webgl.canvas.height;
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 pixelX = (clipspace[0] * 0.5 + 0.5) * super.webgl.canvas.width;
287
- const pixelY = (clipspace[1] * -0.5 + 0.5) * super.webgl.canvas.height;
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 _divEqContainerElement;
9
- private _divHPXContainerElement;
10
- private _divSets;
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
- * @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]
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
- _divEqContainerElement;
9
- _divHPXContainerElement;
10
- _divSets;
11
- _divSetNdx;
12
- constructor() {
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
- // Kept for API parity; nothing required here with current logic.
21
+ GridTextHelper.getLayerState(this.layer);
20
22
  }
21
- resetDivSets() {
22
- // Hide remaining divs and reset index
23
- for (; this._divSetNdx < this._divSets.length; ++this._divSetNdx) {
24
- this._divSets[this._divSetNdx].style.display = 'none';
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
- this._divSetNdx = 0;
28
+ state.divSetNdx = 0;
27
29
  }
28
- /**
29
- * Add / reuse a floating label for HPX coordinates
30
- */
31
30
  addHPXDivSet(msg, x, y) {
32
- let divSet = this._divSets[this._divSetNdx++];
33
- // Create on demand
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
- if (!this._divHPXContainerElement) {
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
- this._divSets.push(divSet);
50
+ state.divSets.push(divSet);
49
51
  }
50
- // Show & position
52
+ divSet.div.className = this.classNameForKind(kind);
51
53
  divSet.style.display = 'block';
52
- divSet.style.left = `${Math.floor(x + 25)}px`;
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
- * Add / reuse a floating label for Equatorial coords
58
- * @param type 'ra' or 'dec'
59
- */
60
- addEqDivSet(msg, x, y, type) {
61
- let divSet = this._divSets[this._divSetNdx++];
62
- if (!divSet) {
63
- const div = document.createElement('div');
64
- const textNode = document.createTextNode('');
65
- div.className = type === 'ra' ? 'floating-div-ra' : 'floating-div-dec';
66
- div.appendChild(textNode);
67
- if (!this._divEqContainerElement) {
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
- divSet.style.display = 'block';
79
- if (type === 'ra') {
80
- divSet.style.left = `${Math.floor(x + 25)}px`;
81
- divSet.style.top = `${Math.floor(y)}px`;
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
- else {
84
- divSet.style.left = `${Math.floor(x)}px`;
85
- divSet.style.top = `${Math.floor(y + 25)}px`;
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
- divSet.textNode.nodeValue = msg;
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 { FoV } from '../FoV.js';
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(): FoV;
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): FoV;
37
- getFoV(): FoV;
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;
@@ -1,10 +1,22 @@
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
  import { AbstractSkyEntity } from '../AbstractSkyEntity.js';
3
15
  import global from '../../Global.js';
4
16
  import { mat4, vec4 } from 'gl-matrix';
5
17
  import { fovHelper } from '../hips/FoVHelper.js';
6
18
  import { FoVUtils } from '../../utils/FoVUtils.js';
7
- import { FoV } from '../FoV.js';
19
+ import { SphereFoV } from '../SphereFoV.js';
8
20
  import { CoordsType } from '../../utils/CoordsType.js';
9
21
  import { Point } from '../Point.js';
10
22
  import GridShaderManager from '../../shader/GridShaderManager.js';
@@ -22,7 +34,7 @@ export class HealpixGrid extends AbstractSkyEntity {
22
34
  fragmentShader;
23
35
  vertexShader;
24
36
  defaultColor = '#ec0acaff';
25
- gridText = new GridTextHelper();
37
+ gridText = new GridTextHelper('healpix');
26
38
  // private _hipsShaderProgram: HiPSShaderProgram
27
39
  _attribLocations = {
28
40
  position: 0,
@@ -59,7 +71,7 @@ export class HealpixGrid extends AbstractSkyEntity {
59
71
  this._vertexCataloguePositionBuffer = super.webgl.createBuffer();
60
72
  this._indexBuffer = super.webgl.createBuffer();
61
73
  this._vertexCataloguePosition = new Float32Array(0);
62
- this._fovObj = new FoV(super.webgl);
74
+ this._fovObj = new SphereFoV(super.webgl);
63
75
  }
64
76
  get fovObj() {
65
77
  return this._fovObj;
@@ -288,9 +300,10 @@ export class HealpixGrid extends AbstractSkyEntity {
288
300
  // NDC divide
289
301
  clipspace[0] /= clipspace[3];
290
302
  clipspace[1] /= clipspace[3];
291
- // clip → pixels
292
- const pixelX = (clipspace[0] * 0.5 + 0.5) * gl.canvas.width;
293
- const pixelY = (clipspace[1] * -0.5 + 0.5) * gl.canvas.height;
303
+ // clip -> CSS pixels
304
+ const canvasRect = gl.canvas.getBoundingClientRect();
305
+ const pixelX = canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width;
306
+ const pixelY = canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height;
294
307
  this.gridText.addHPXDivSet(this._visibleorder + '/' + pixels[p], pixelX, pixelY);
295
308
  // gridTextHelper.addHPXDivSet(this._visibleorder + '/' + pixels[p], pixelX, pixelY);
296
309
  }