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
@@ -5,6 +5,18 @@
5
5
  /***/ 146:
6
6
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
7
7
 
8
+ /*
9
+ * AstroViewer
10
+ * Copyright (C) Fabrizio Giordano
11
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
12
+ *
13
+ * This file is part of AstroViewer.
14
+ * AstroViewer is distributed under a dual-license model.
15
+ * Commercial use requires a separate commercial license.
16
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17
+ *
18
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
19
+ */
8
20
 
9
21
  var __importDefault = (this && this.__importDefault) || function (mod) {
10
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -78,15 +90,36 @@ exports.Source = Source;
78
90
  /***/ }),
79
91
 
80
92
  /***/ 149:
81
- /***/ ((__unused_webpack_module, exports) => {
93
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
82
94
 
83
95
 
96
+ /*
97
+ * AstroViewer
98
+ * Copyright (C) Fabrizio Giordano
99
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
100
+ *
101
+ * This file is part of AstroViewer.
102
+ * AstroViewer is distributed under a dual-license model.
103
+ * Commercial use requires a separate commercial license.
104
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
105
+ *
106
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
107
+ */
84
108
  Object.defineProperty(exports, "__esModule", ({ value: true }));
85
109
  exports.XYZShaderProgram = void 0;
110
+ const ColorMaps_js_1 = __webpack_require__(619);
86
111
  class XYZShaderProgram {
87
112
  locations;
88
113
  _webgl;
89
114
  _shaderProgram;
115
+ _colorMapBlockIndex = null;
116
+ _colorMapBuffer = null;
117
+ _runtimeColorMap;
118
+ _colorMapVariableInfo = {
119
+ r_palette: { index: 0, offset: 0 },
120
+ g_palette: { index: 0, offset: 0 },
121
+ b_palette: { index: 0, offset: 0 },
122
+ };
90
123
  constructor(webgl) {
91
124
  this._webgl = webgl;
92
125
  this.locations = {
@@ -94,6 +127,7 @@ class XYZShaderProgram {
94
127
  mMatrix: null,
95
128
  vMatrix: null,
96
129
  sampler: null,
130
+ colorMapIdx: null,
97
131
  vertexPositionAttribute: -1,
98
132
  textureCoordAttribute: -1,
99
133
  };
@@ -114,7 +148,10 @@ class XYZShaderProgram {
114
148
  enableProgram() {
115
149
  this._webgl.useProgram(this.shaderProgram);
116
150
  }
117
- enableShaders(pMatrix, vMatrix, mMatrix) {
151
+ setRuntimeColorMap(colorMap) {
152
+ this._runtimeColorMap = colorMap;
153
+ }
154
+ enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx = 0) {
118
155
  const gl = this._webgl;
119
156
  const program = this.shaderProgram;
120
157
  gl.useProgram(program);
@@ -122,12 +159,17 @@ class XYZShaderProgram {
122
159
  this.locations.mMatrix = gl.getUniformLocation(program, 'uMMatrix');
123
160
  this.locations.vMatrix = gl.getUniformLocation(program, 'uVMatrix');
124
161
  this.locations.sampler = gl.getUniformLocation(program, 'uSampler');
162
+ this.locations.colorMapIdx = gl.getUniformLocation(program, 'cmapIdx');
125
163
  this.locations.vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition');
126
164
  this.locations.textureCoordAttribute = gl.getAttribLocation(program, 'aTextureCoord');
127
165
  gl.uniformMatrix4fv(this.locations.pMatrix, false, pMatrix);
128
166
  gl.uniformMatrix4fv(this.locations.vMatrix, false, vMatrix);
129
167
  gl.uniformMatrix4fv(this.locations.mMatrix, false, mMatrix);
130
168
  gl.uniform1i(this.locations.sampler, 0);
169
+ gl.uniform1i(this.locations.colorMapIdx, colorMapIdx);
170
+ if (colorMapIdx >= 2) {
171
+ this.uploadColorMap(colorMapIdx);
172
+ }
131
173
  }
132
174
  initShaders() {
133
175
  const gl = this._webgl;
@@ -146,9 +188,40 @@ class XYZShaderProgram {
146
188
  precision mediump float;
147
189
  in vec2 vTextureCoord;
148
190
  uniform sampler2D uSampler;
191
+ uniform int cmapIdx;
192
+
193
+ layout (std140) uniform colormap {
194
+ float r_palette[256];
195
+ float g_palette[256];
196
+ float b_palette[256];
197
+ };
198
+
149
199
  out vec4 outColor;
200
+
150
201
  void main(void) {
151
- outColor = texture(uSampler, vTextureCoord);
202
+ vec4 color = texture(uSampler, vTextureCoord);
203
+
204
+ if (cmapIdx == 1) {
205
+ float gray = 0.21 * color.r + 0.71 * color.g + 0.07 * color.b;
206
+ outColor = vec4(vec3(gray), color.a);
207
+ return;
208
+ }
209
+
210
+ if (cmapIdx >= 2) {
211
+ int rIndex = int(clamp(color.r * 255.0, 0.0, 255.0));
212
+ int gIndex = int(clamp(color.g * 255.0, 0.0, 255.0));
213
+ int bIndex = int(clamp(color.b * 255.0, 0.0, 255.0));
214
+
215
+ outColor = vec4(
216
+ r_palette[rIndex] / 256.0,
217
+ g_palette[gIndex] / 256.0,
218
+ b_palette[bIndex] / 256.0,
219
+ color.a
220
+ );
221
+ return;
222
+ }
223
+
224
+ outColor = color;
152
225
  }`);
153
226
  gl.attachShader(this._shaderProgram, vertexShader);
154
227
  gl.attachShader(this._shaderProgram, fragmentShader);
@@ -156,6 +229,7 @@ class XYZShaderProgram {
156
229
  if (!gl.getProgramParameter(this._shaderProgram, gl.LINK_STATUS)) {
157
230
  throw new Error(gl.getProgramInfoLog(this._shaderProgram) || 'Could not initialise XYZ shaders');
158
231
  }
232
+ this.initColorMapBuffer();
159
233
  }
160
234
  compileShader(type, source) {
161
235
  const gl = this._webgl;
@@ -170,6 +244,69 @@ class XYZShaderProgram {
170
244
  }
171
245
  return shader;
172
246
  }
247
+ initColorMapBuffer() {
248
+ const gl = this._webgl;
249
+ const program = this._shaderProgram;
250
+ const blockIndex = gl.getUniformBlockIndex(program, 'colormap');
251
+ if (blockIndex === gl.INVALID_INDEX) {
252
+ this._colorMapBlockIndex = null;
253
+ return;
254
+ }
255
+ this._colorMapBlockIndex = blockIndex;
256
+ const variableNames = ['r_palette', 'g_palette', 'b_palette'];
257
+ const variableIndices = gl.getUniformIndices(program, variableNames);
258
+ const variableOffsets = gl.getActiveUniforms(program, variableIndices, gl.UNIFORM_OFFSET);
259
+ variableNames.forEach((name, index) => {
260
+ this._colorMapVariableInfo[name] = {
261
+ index: variableIndices[index],
262
+ offset: variableOffsets[index],
263
+ };
264
+ });
265
+ this._colorMapBuffer = gl.createBuffer();
266
+ gl.bindBuffer(gl.UNIFORM_BUFFER, this._colorMapBuffer);
267
+ gl.bufferData(gl.UNIFORM_BUFFER, 3 * 4096, gl.STATIC_DRAW);
268
+ gl.bindBuffer(gl.UNIFORM_BUFFER, null);
269
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, this._colorMapBuffer);
270
+ gl.uniformBlockBinding(program, blockIndex, 0);
271
+ }
272
+ uploadColorMap(colorMapIdx) {
273
+ if (!this._colorMapBuffer || this._colorMapBlockIndex === null) {
274
+ return;
275
+ }
276
+ const colorMap = this.getColorMap(colorMapIdx);
277
+ if (!colorMap) {
278
+ return;
279
+ }
280
+ const gl = this._webgl;
281
+ const program = this.shaderProgram;
282
+ gl.uniformBlockBinding(program, this._colorMapBlockIndex, 0);
283
+ gl.bindBuffer(gl.UNIFORM_BUFFER, this._colorMapBuffer);
284
+ const info = this._colorMapVariableInfo;
285
+ gl.bufferSubData(gl.UNIFORM_BUFFER, info.r_palette.offset, colorMap.r, 0);
286
+ gl.bufferSubData(gl.UNIFORM_BUFFER, info.g_palette.offset, colorMap.g, 0);
287
+ gl.bufferSubData(gl.UNIFORM_BUFFER, info.b_palette.offset, colorMap.b, 0);
288
+ gl.bindBuffer(gl.UNIFORM_BUFFER, null);
289
+ }
290
+ getColorMap(colorMapIdx) {
291
+ switch (colorMapIdx) {
292
+ case 2:
293
+ return ColorMaps_js_1.ColorMaps.planck;
294
+ case 3:
295
+ return ColorMaps_js_1.ColorMaps.cmb;
296
+ case 4:
297
+ return ColorMaps_js_1.ColorMaps.rainbow;
298
+ case 5:
299
+ return ColorMaps_js_1.ColorMaps.eosb;
300
+ case 6:
301
+ return ColorMaps_js_1.ColorMaps.cubehelix;
302
+ case 7:
303
+ return ColorMaps_js_1.ColorMaps.hot;
304
+ case 8:
305
+ return ColorMaps_js_1.ColorMaps.gray;
306
+ default:
307
+ return this._runtimeColorMap;
308
+ }
309
+ }
173
310
  }
174
311
  exports.XYZShaderProgram = XYZShaderProgram;
175
312
 
@@ -179,6 +316,18 @@ exports.XYZShaderProgram = XYZShaderProgram;
179
316
  /***/ 229:
180
317
  /***/ ((__unused_webpack_module, exports) => {
181
318
 
319
+ /*
320
+ * AstroViewer
321
+ * Copyright (C) Fabrizio Giordano
322
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
323
+ *
324
+ * This file is part of AstroViewer.
325
+ * AstroViewer is distributed under a dual-license model.
326
+ * Commercial use requires a separate commercial license.
327
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
328
+ *
329
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
330
+ */
182
331
  // FoVHelper.ts
183
332
 
184
333
  Object.defineProperty(exports, "__esModule", ({ value: true }));
@@ -289,54 +438,24 @@ exports.fovHelper = new FoVHelper();
289
438
  exports["default"] = FoVHelper;
290
439
 
291
440
 
292
- /***/ }),
293
-
294
- /***/ 497:
295
- /***/ ((__unused_webpack_module, exports) => {
296
-
297
-
298
- Object.defineProperty(exports, "__esModule", ({ value: true }));
299
- exports.XYZAncestorMeshCache = void 0;
300
- class XYZAncestorMeshCache {
301
- _webgl;
302
- _meshBuilder;
303
- _meshes = new Map();
304
- constructor(webgl, meshBuilder) {
305
- this._webgl = webgl;
306
- this._meshBuilder = meshBuilder;
307
- }
308
- getMesh(targetTile, ancestorTile, segmentsPerSide) {
309
- const key = `${targetTile.z}/${targetTile.x}/${targetTile.y}->${ancestorTile.z}/${ancestorTile.x}/${ancestorTile.y}@${segmentsPerSide}`;
310
- const existing = this._meshes.get(key);
311
- if (existing) {
312
- return existing;
313
- }
314
- const mesh = this._meshBuilder.buildAncestorMesh(targetTile, ancestorTile, segmentsPerSide);
315
- const uploaded = this._meshBuilder.uploadMesh(mesh, this._webgl);
316
- this._meshes.set(key, uploaded);
317
- return uploaded;
318
- }
319
- dispose() {
320
- for (const mesh of this._meshes.values()) {
321
- if (mesh.positionBuffer)
322
- this._webgl.deleteBuffer(mesh.positionBuffer);
323
- if (mesh.uvBuffer)
324
- this._webgl.deleteBuffer(mesh.uvBuffer);
325
- if (mesh.indexBuffer)
326
- this._webgl.deleteBuffer(mesh.indexBuffer);
327
- }
328
- this._meshes.clear();
329
- }
330
- }
331
- exports.XYZAncestorMeshCache = XYZAncestorMeshCache;
332
-
333
-
334
441
  /***/ }),
335
442
 
336
443
  /***/ 592:
337
444
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
338
445
 
339
446
 
447
+ /*
448
+ * AstroViewer
449
+ * Copyright (C) Fabrizio Giordano
450
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
451
+ *
452
+ * This file is part of AstroViewer.
453
+ * AstroViewer is distributed under a dual-license model.
454
+ * Commercial use requires a separate commercial license.
455
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
456
+ *
457
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
458
+ */
340
459
  var __importDefault = (this && this.__importDefault) || function (mod) {
341
460
  return (mod && mod.__esModule) ? mod : { "default": mod };
342
461
  };
@@ -942,6 +1061,18 @@ exports.FootprintSetGL = FootprintSetGL;
942
1061
  /***/ ((__unused_webpack_module, exports) => {
943
1062
 
944
1063
 
1064
+ /*
1065
+ * AstroViewer
1066
+ * Copyright (C) Fabrizio Giordano
1067
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
1068
+ *
1069
+ * This file is part of AstroViewer.
1070
+ * AstroViewer is distributed under a dual-license model.
1071
+ * Commercial use requires a separate commercial license.
1072
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
1073
+ *
1074
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
1075
+ */
945
1076
  Object.defineProperty(exports, "__esModule", ({ value: true }));
946
1077
  exports.ColorMaps = exports.COLOR_MAP_SAMPLE_COUNT = void 0;
947
1078
  exports.createColorMapFromSamples = createColorMapFromSamples;
@@ -2240,6 +2371,18 @@ exports["default"] = exports.ColorMaps;
2240
2371
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
2241
2372
 
2242
2373
 
2374
+ /*
2375
+ * AstroViewer
2376
+ * Copyright (C) Fabrizio Giordano
2377
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
2378
+ *
2379
+ * This file is part of AstroViewer.
2380
+ * AstroViewer is distributed under a dual-license model.
2381
+ * Commercial use requires a separate commercial license.
2382
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
2383
+ *
2384
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
2385
+ */
2243
2386
  var __importDefault = (this && this.__importDefault) || function (mod) {
2244
2387
  return (mod && mod.__esModule) ? mod : { "default": mod };
2245
2388
  };
@@ -2253,6 +2396,7 @@ const FootprintSetGL_js_1 = __webpack_require__(592);
2253
2396
  const Config_js_1 = __webpack_require__(2919);
2254
2397
  const ColorMaps_js_1 = __importDefault(__webpack_require__(619));
2255
2398
  const XYZTileRequestScheduler_js_1 = __webpack_require__(5409);
2399
+ const XYZMapDescriptor_js_1 = __webpack_require__(8868);
2256
2400
  const TerraPointSetGL_js_1 = __webpack_require__(5781);
2257
2401
  const TerraFootprintSetGL_js_1 = __webpack_require__(9022);
2258
2402
  // & {
@@ -2363,6 +2507,10 @@ class AstroViewer {
2363
2507
  activateXYZ(config) {
2364
2508
  this.astroSphere.activateXYZ(config);
2365
2509
  }
2510
+ activateXYZ2(config) {
2511
+ const descriptor = new XYZMapDescriptor_js_1.XYZMapDescriptor(config.name ?? 'XYZ Earth2 Layer', config.urlTemplate, config.minZoom ?? 0, config.maxZoom ?? 8, config.segmentsPerSide ?? 48, config.maxCachedTiles ?? 384, 8, config.urlResolver);
2512
+ this.astroSphere.activateXYZ2(descriptor);
2513
+ }
2366
2514
  activateWMTS(config) {
2367
2515
  this.astroSphere.activateWMTS(config);
2368
2516
  }
@@ -2421,6 +2569,9 @@ class AstroViewer {
2421
2569
  // console.log(`AstroViewer.goTo goto(${raDeg}, ${decDeg})`)
2422
2570
  this.astroSphere.goTo(raDeg, decDeg);
2423
2571
  }
2572
+ getActiveCoordinateMode() {
2573
+ return this.astroSphere.getActiveCoordinateMode();
2574
+ }
2424
2575
  getCenterCoordinates() {
2425
2576
  return this.astroSphere.getCentralPointCoordinates();
2426
2577
  }
@@ -2447,6 +2598,33 @@ class AstroViewer {
2447
2598
  // return equatorialGridSingleton.isVisible()
2448
2599
  return this.astroSphere.equatorialGrid.isVisible();
2449
2600
  }
2601
+ toggleLonLatGrid() {
2602
+ return this.astroSphere.toggleLonLatGrid();
2603
+ }
2604
+ isLonLatGridVisible() {
2605
+ return this.astroSphere.isLonLatGridVisible();
2606
+ }
2607
+ setEastWestRotationLocked(locked) {
2608
+ this.astroSphere.setEastWestRotationLocked(locked);
2609
+ }
2610
+ isEastWestRotationLocked() {
2611
+ return this.astroSphere.isEastWestRotationLocked();
2612
+ }
2613
+ setNorthSouthRotationLocked(locked) {
2614
+ this.astroSphere.setNorthSouthRotationLocked(locked);
2615
+ }
2616
+ isNorthSouthRotationLocked() {
2617
+ return this.astroSphere.isNorthSouthRotationLocked();
2618
+ }
2619
+ resetAxesOrientation() {
2620
+ this.astroSphere.resetAxesOrientation();
2621
+ }
2622
+ setKeepCameraNorthUp(enabled) {
2623
+ this.astroSphere.setKeepCameraNorthUp(enabled);
2624
+ }
2625
+ isKeepCameraNorthUp() {
2626
+ return this.astroSphere.isKeepCameraNorthUp();
2627
+ }
2450
2628
  // FOV
2451
2629
  getFoV() {
2452
2630
  return this.astroSphere.getFoV();
@@ -2646,6 +2824,18 @@ exports.AstroViewer = AstroViewer;
2646
2824
  /***/ 1072:
2647
2825
  /***/ ((__unused_webpack_module, exports) => {
2648
2826
 
2827
+ /*
2828
+ * AstroViewer
2829
+ * Copyright (C) Fabrizio Giordano
2830
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
2831
+ *
2832
+ * This file is part of AstroViewer.
2833
+ * AstroViewer is distributed under a dual-license model.
2834
+ * Commercial use requires a separate commercial license.
2835
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
2836
+ *
2837
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
2838
+ */
2649
2839
 
2650
2840
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2651
2841
  exports.MetadataColumn = exports.ColumnType = void 0;
@@ -4187,6 +4377,18 @@ class Healpix {
4187
4377
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4188
4378
 
4189
4379
 
4380
+ /*
4381
+ * AstroViewer
4382
+ * Copyright (C) Fabrizio Giordano
4383
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
4384
+ *
4385
+ * This file is part of AstroViewer.
4386
+ * AstroViewer is distributed under a dual-license model.
4387
+ * Commercial use requires a separate commercial license.
4388
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
4389
+ *
4390
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
4391
+ */
4190
4392
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4191
4393
  exports.CatalogueGL = void 0;
4192
4394
  const Source_js_1 = __webpack_require__(146);
@@ -4811,57 +5013,58 @@ exports.CatalogueGL = CatalogueGL;
4811
5013
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4812
5014
 
4813
5015
 
5016
+ /*
5017
+ * AstroViewer
5018
+ * Copyright (C) Fabrizio Giordano
5019
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
5020
+ *
5021
+ * This file is part of AstroViewer.
5022
+ * AstroViewer is distributed under a dual-license model.
5023
+ * Commercial use requires a separate commercial license.
5024
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
5025
+ *
5026
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
5027
+ */
4814
5028
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4815
5029
  exports.XYZTile = void 0;
4816
- const XYZTileRequestScheduler_js_1 = __webpack_require__(5409);
5030
+ const XYZMeshBuilder_js_1 = __webpack_require__(8819);
4817
5031
  class XYZTile {
4818
5032
  _coord;
4819
5033
  _url;
4820
5034
  _webgl;
4821
5035
  _shaderProgram;
4822
- _positionBuffer;
4823
- _uvBuffer;
4824
- _indexBuffer;
5036
+ _meshBuilder;
5037
+ _gpuMesh;
4825
5038
  _texture = null;
4826
- _indices;
4827
- _indexType;
5039
+ _image;
4828
5040
  _ready = false;
4829
- _aborted = false;
4830
5041
  _loading = false;
5042
+ _aborted = false;
4831
5043
  _failedUntil = 0;
4832
5044
  _lastUsedAt = 0;
4833
5045
  _createdAt = Date.now();
4834
- _image;
4835
- _objectUrl = null;
4836
- constructor(coord, url, mesh, webgl, shaderProgram) {
5046
+ constructor(coord, url, webgl, shaderProgram, meshBuilder = new XYZMeshBuilder_js_1.XYZMeshBuilder(), segmentsPerSide = 16) {
4837
5047
  this._coord = coord;
4838
5048
  this._url = url;
4839
5049
  this._webgl = webgl;
4840
5050
  this._shaderProgram = shaderProgram;
4841
- this._positionBuffer = webgl.createBuffer();
4842
- this._uvBuffer = webgl.createBuffer();
4843
- this._indexBuffer = webgl.createBuffer();
4844
- this._indices = mesh.indices;
4845
- this._indexType = mesh.indices instanceof Uint32Array ? webgl.UNSIGNED_INT : webgl.UNSIGNED_SHORT;
4846
- webgl.bindBuffer(webgl.ARRAY_BUFFER, this._positionBuffer);
4847
- webgl.bufferData(webgl.ARRAY_BUFFER, mesh.positions, webgl.STATIC_DRAW);
4848
- webgl.bindBuffer(webgl.ARRAY_BUFFER, this._uvBuffer);
4849
- webgl.bufferData(webgl.ARRAY_BUFFER, mesh.uvs, webgl.STATIC_DRAW);
4850
- webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
4851
- webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, mesh.indices, webgl.STATIC_DRAW);
4852
- }
4853
- get ready() {
4854
- return this._ready;
5051
+ this._meshBuilder = meshBuilder;
5052
+ const mesh = this._meshBuilder.buildTileMesh(coord, segmentsPerSide);
5053
+ this._gpuMesh = this._meshBuilder.uploadMesh(mesh, this._webgl);
5054
+ this.initImage();
4855
5055
  }
4856
5056
  get coord() {
4857
5057
  return this._coord;
4858
5058
  }
4859
- get failedUntil() {
4860
- return this._failedUntil;
5059
+ get ready() {
5060
+ return this._ready;
4861
5061
  }
4862
5062
  get loading() {
4863
5063
  return this._loading;
4864
5064
  }
5065
+ get failedUntil() {
5066
+ return this._failedUntil;
5067
+ }
4865
5068
  get lastUsedAt() {
4866
5069
  return this._lastUsedAt;
4867
5070
  }
@@ -4871,10 +5074,7 @@ class XYZTile {
4871
5074
  touch() {
4872
5075
  this._lastUsedAt = Date.now();
4873
5076
  }
4874
- primeLoad(priority = 0) {
4875
- this.loadTexture(priority);
4876
- }
4877
- loadTexture(priority = 0) {
5077
+ initImage() {
4878
5078
  if (this._loading || this._ready || this._aborted) {
4879
5079
  return;
4880
5080
  }
@@ -4883,80 +5083,88 @@ class XYZTile {
4883
5083
  return;
4884
5084
  }
4885
5085
  this._loading = true;
4886
- XYZTileRequestScheduler_js_1.xyzTileRequestScheduler.load(this._url, priority)
4887
- .then((blob) => this.loadImageFromBlob(blob))
4888
- .catch((error) => {
4889
- this._loading = false;
4890
- this._ready = false;
4891
- const cooldownMs = error instanceof XYZTileRequestScheduler_js_1.XYZTileRequestError ? error.cooldownMs : 10000;
4892
- this._failedUntil = Date.now() + cooldownMs;
4893
- });
4894
- }
4895
- loadImageFromBlob(blob) {
4896
5086
  const image = new Image();
4897
5087
  this._image = image;
4898
- this._objectUrl = URL.createObjectURL(blob);
4899
- image.onload = () => this.onImageLoaded();
5088
+ image.crossOrigin = 'anonymous';
5089
+ image.onload = () => this.imageLoaded();
4900
5090
  image.onerror = () => {
4901
- this._loading = false;
4902
5091
  this._ready = false;
4903
- this._failedUntil = Date.now() + 30000;
4904
- this.revokeObjectUrl();
5092
+ this._loading = false;
5093
+ this._failedUntil = Date.now() + 30_000;
4905
5094
  };
4906
- image.src = this._objectUrl;
5095
+ image.src = this._url;
4907
5096
  }
4908
- onImageLoaded() {
5097
+ imageLoaded() {
4909
5098
  if (!this._image || this._aborted) {
4910
5099
  return;
4911
5100
  }
5101
+ this.textureLoaded(this._image);
5102
+ this._loading = false;
5103
+ this._failedUntil = 0;
5104
+ this._ready = true;
5105
+ }
5106
+ textureLoaded(image) {
4912
5107
  const gl = this._webgl;
5108
+ this._shaderProgram.enableProgram();
4913
5109
  const texture = gl.createTexture();
4914
5110
  if (!texture) {
4915
- throw new Error('Could not create XYZ texture');
5111
+ throw new Error(`Could not create XYZ texture for ${this.key}`);
4916
5112
  }
4917
5113
  this._texture = texture;
4918
5114
  gl.activeTexture(gl.TEXTURE0);
4919
- gl.bindTexture(gl.TEXTURE_2D, texture);
4920
5115
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
4921
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
5116
+ gl.bindTexture(gl.TEXTURE_2D, texture);
5117
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
4922
5118
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
4923
5119
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
4924
5120
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
4925
5121
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
4926
- this._loading = false;
4927
- this._failedUntil = 0;
4928
- this._ready = true;
4929
- this.revokeObjectUrl();
4930
5122
  }
4931
- draw(pMatrix, vMatrix, mMatrix, priority = 0, allowLoad = true) {
5123
+ draw(pMatrix, vMatrix, mMatrix, colorMapIdx) {
4932
5124
  this.touch();
4933
- if (!this._ready && allowLoad) {
4934
- this.loadTexture(priority);
4935
- }
4936
- if (!this._ready || !this._texture) {
4937
- return;
5125
+ if (!this._ready || !this._texture || this._aborted) {
5126
+ return false;
4938
5127
  }
4939
- this.drawWithGpuMesh({
4940
- positionBuffer: this._positionBuffer,
4941
- uvBuffer: this._uvBuffer,
4942
- indexBuffer: this._indexBuffer,
4943
- indexCount: this._indices.length,
4944
- indexType: this._indexType,
4945
- }, pMatrix, vMatrix, mMatrix);
5128
+ this.drawWithGpuMesh(this._gpuMesh, pMatrix, vMatrix, mMatrix, colorMapIdx);
5129
+ return true;
4946
5130
  }
4947
- drawRemapped(mesh, pMatrix, vMatrix, mMatrix) {
5131
+ drawRemapped(mesh, pMatrix, vMatrix, mMatrix, colorMapIdx) {
4948
5132
  this.touch();
4949
- if (!this._ready || !this._texture) {
4950
- return;
5133
+ if (!this._ready || !this._texture || this._aborted) {
5134
+ return false;
5135
+ }
5136
+ this.drawWithGpuMesh(mesh, pMatrix, vMatrix, mMatrix, colorMapIdx);
5137
+ return true;
5138
+ }
5139
+ dispose() {
5140
+ const gl = this._webgl;
5141
+ if (this._texture) {
5142
+ gl.deleteTexture(this._texture);
5143
+ this._texture = null;
4951
5144
  }
4952
- this.drawWithGpuMesh(mesh, pMatrix, vMatrix, mMatrix);
5145
+ if (this._gpuMesh.positionBuffer) {
5146
+ gl.deleteBuffer(this._gpuMesh.positionBuffer);
5147
+ this._gpuMesh.positionBuffer = null;
5148
+ }
5149
+ if (this._gpuMesh.uvBuffer) {
5150
+ gl.deleteBuffer(this._gpuMesh.uvBuffer);
5151
+ this._gpuMesh.uvBuffer = null;
5152
+ }
5153
+ if (this._gpuMesh.indexBuffer) {
5154
+ gl.deleteBuffer(this._gpuMesh.indexBuffer);
5155
+ this._gpuMesh.indexBuffer = null;
5156
+ }
5157
+ this._image = undefined;
5158
+ this._ready = false;
5159
+ this._loading = false;
5160
+ this._aborted = true;
4953
5161
  }
4954
- drawWithGpuMesh(mesh, pMatrix, vMatrix, mMatrix) {
5162
+ drawWithGpuMesh(mesh, pMatrix, vMatrix, mMatrix, colorMapIdx) {
4955
5163
  if (!this._texture) {
4956
5164
  return;
4957
5165
  }
4958
5166
  const gl = this._webgl;
4959
- this._shaderProgram.enableShaders(pMatrix, vMatrix, mMatrix);
5167
+ this._shaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx);
4960
5168
  gl.bindBuffer(gl.ARRAY_BUFFER, mesh.positionBuffer);
4961
5169
  gl.vertexAttribPointer(this._shaderProgram.locations.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
4962
5170
  gl.enableVertexAttribArray(this._shaderProgram.locations.vertexPositionAttribute);
@@ -4970,34 +5178,8 @@ class XYZTile {
4970
5178
  gl.disableVertexAttribArray(this._shaderProgram.locations.vertexPositionAttribute);
4971
5179
  gl.disableVertexAttribArray(this._shaderProgram.locations.textureCoordAttribute);
4972
5180
  }
4973
- dispose() {
4974
- const gl = this._webgl;
4975
- if (this._texture) {
4976
- gl.deleteTexture(this._texture);
4977
- this._texture = null;
4978
- }
4979
- if (this._positionBuffer) {
4980
- gl.deleteBuffer(this._positionBuffer);
4981
- this._positionBuffer = null;
4982
- }
4983
- if (this._uvBuffer) {
4984
- gl.deleteBuffer(this._uvBuffer);
4985
- this._uvBuffer = null;
4986
- }
4987
- if (this._indexBuffer) {
4988
- gl.deleteBuffer(this._indexBuffer);
4989
- this._indexBuffer = null;
4990
- }
4991
- this._image = undefined;
4992
- this.revokeObjectUrl();
4993
- this._loading = false;
4994
- this._ready = false;
4995
- }
4996
- revokeObjectUrl() {
4997
- if (this._objectUrl) {
4998
- URL.revokeObjectURL(this._objectUrl);
4999
- this._objectUrl = null;
5000
- }
5181
+ get key() {
5182
+ return `${this._coord.z}/${this._coord.x}/${this._coord.y}`;
5001
5183
  }
5002
5184
  }
5003
5185
  exports.XYZTile = XYZTile;
@@ -5005,79 +5187,298 @@ exports.XYZTile = XYZTile;
5005
5187
 
5006
5188
  /***/ }),
5007
5189
 
5008
- /***/ 1961:
5009
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
5010
-
5011
- // ESM COMPAT FLAG
5012
- __webpack_require__.r(__webpack_exports__);
5013
-
5014
- // EXPORTS
5015
- __webpack_require__.d(__webpack_exports__, {
5016
- glMatrix: () => (/* reexport */ common_namespaceObject),
5017
- mat2: () => (/* reexport */ mat2_namespaceObject),
5018
- mat2d: () => (/* reexport */ mat2d_namespaceObject),
5019
- mat3: () => (/* reexport */ mat3_namespaceObject),
5020
- mat4: () => (/* reexport */ mat4_namespaceObject),
5021
- quat: () => (/* reexport */ quat_namespaceObject),
5022
- quat2: () => (/* reexport */ quat2_namespaceObject),
5023
- vec2: () => (/* reexport */ vec2_namespaceObject),
5024
- vec3: () => (/* reexport */ vec3_namespaceObject),
5025
- vec4: () => (/* reexport */ vec4_namespaceObject)
5026
- });
5027
-
5028
- // NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/common.js
5029
- var common_namespaceObject = {};
5030
- __webpack_require__.r(common_namespaceObject);
5031
- __webpack_require__.d(common_namespaceObject, {
5032
- ANGLE_ORDER: () => (ANGLE_ORDER),
5033
- ARRAY_TYPE: () => (ARRAY_TYPE),
5034
- EPSILON: () => (EPSILON),
5035
- RANDOM: () => (RANDOM),
5036
- equals: () => (equals),
5037
- round: () => (round),
5038
- setMatrixArrayType: () => (setMatrixArrayType),
5039
- toDegree: () => (toDegree),
5040
- toRadian: () => (toRadian)
5041
- });
5190
+ /***/ 1741:
5191
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5042
5192
 
5043
- // NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat2.js
5044
- var mat2_namespaceObject = {};
5045
- __webpack_require__.r(mat2_namespaceObject);
5046
- __webpack_require__.d(mat2_namespaceObject, {
5047
- LDU: () => (LDU),
5048
- add: () => (add),
5049
- adjoint: () => (adjoint),
5050
- clone: () => (clone),
5051
- copy: () => (copy),
5052
- create: () => (create),
5053
- determinant: () => (determinant),
5054
- equals: () => (mat2_equals),
5055
- exactEquals: () => (exactEquals),
5056
- frob: () => (frob),
5057
- fromRotation: () => (fromRotation),
5058
- fromScaling: () => (fromScaling),
5059
- fromValues: () => (fromValues),
5060
- identity: () => (identity),
5061
- invert: () => (invert),
5062
- mul: () => (mul),
5063
- multiply: () => (multiply),
5064
- multiplyScalar: () => (multiplyScalar),
5065
- multiplyScalarAndAdd: () => (multiplyScalarAndAdd),
5066
- rotate: () => (rotate),
5067
- scale: () => (scale),
5068
- set: () => (set),
5069
- str: () => (str),
5070
- sub: () => (sub),
5071
- subtract: () => (subtract),
5072
- transpose: () => (transpose)
5073
- });
5074
5193
 
5075
- // NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat2d.js
5076
- var mat2d_namespaceObject = {};
5077
- __webpack_require__.r(mat2d_namespaceObject);
5078
- __webpack_require__.d(mat2d_namespaceObject, {
5079
- add: () => (mat2d_add),
5080
- clone: () => (mat2d_clone),
5194
+ /*
5195
+ * AstroViewer
5196
+ * Copyright (C) Fabrizio Giordano
5197
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
5198
+ *
5199
+ * This file is part of AstroViewer.
5200
+ * AstroViewer is distributed under a dual-license model.
5201
+ * Commercial use requires a separate commercial license.
5202
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
5203
+ *
5204
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
5205
+ */
5206
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
5207
+ exports.XYZMap = void 0;
5208
+ const AbstractSkyEntity_js_1 = __webpack_require__(4735);
5209
+ const XYZVisibleTilesManager_js_1 = __webpack_require__(6937);
5210
+ const XYZFoVHelper_js_1 = __webpack_require__(8284);
5211
+ const ColorMaps_js_1 = __webpack_require__(619);
5212
+ const LonLatGrid_js_1 = __webpack_require__(8124);
5213
+ const XYZShaderProgram_js_1 = __webpack_require__(149);
5214
+ const XYZTileBuffer_js_1 = __webpack_require__(2737);
5215
+ const XYZAnchestorTile_js_1 = __webpack_require__(3174);
5216
+ const XYZMeshBuilder_js_1 = __webpack_require__(8819);
5217
+ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
5218
+ _xyzShaderProgram;
5219
+ _descriptor;
5220
+ _visibleTilesManager;
5221
+ _tileBuffer;
5222
+ _meshBuilder;
5223
+ _baseurl;
5224
+ _zoom;
5225
+ _latLonGrid;
5226
+ _colorMapIdx = 0;
5227
+ _colorMap = ColorMaps_js_1.ColorMaps['native'];
5228
+ constructor(radius, position, xrad, yrad, descriptor, webgl) {
5229
+ super(radius, position, xrad, yrad, descriptor.name, webgl, false);
5230
+ this._descriptor = descriptor;
5231
+ this._xyzShaderProgram = new XYZShaderProgram_js_1.XYZShaderProgram(webgl);
5232
+ this._meshBuilder = new XYZMeshBuilder_js_1.XYZMeshBuilder();
5233
+ this._tileBuffer = new XYZTileBuffer_js_1.XYZTileBuffer(1);
5234
+ this.initGL(webgl);
5235
+ this._latLonGrid = new LonLatGrid_js_1.LatLonGrid(radius, position, xrad, yrad, 'LatLonGrid', this._webgl);
5236
+ this._visibleTilesManager = new XYZVisibleTilesManager_js_1.XYZVisibleTilesManager();
5237
+ this._baseurl = descriptor.url;
5238
+ this.initShaders();
5239
+ const fov = 180;
5240
+ this._zoom = XYZFoVHelper_js_1.xyzFovHelper.getZoom(fov);
5241
+ }
5242
+ changeColorMap(colorMap) {
5243
+ this._colorMap = colorMap;
5244
+ switch (colorMap.name) {
5245
+ case 'grayscale':
5246
+ this._colorMapIdx = 1;
5247
+ this._colorMap = ColorMaps_js_1.ColorMaps['grayscale'];
5248
+ break;
5249
+ case 'planck':
5250
+ this._colorMapIdx = 2;
5251
+ this._colorMap = ColorMaps_js_1.ColorMaps['planck'];
5252
+ break;
5253
+ case 'cmb':
5254
+ this._colorMapIdx = 3;
5255
+ this._colorMap = ColorMaps_js_1.ColorMaps['cmb'];
5256
+ break;
5257
+ case 'rainbow':
5258
+ this._colorMapIdx = 4;
5259
+ this._colorMap = ColorMaps_js_1.ColorMaps['rainbow'];
5260
+ break;
5261
+ case 'eosb':
5262
+ this._colorMapIdx = 5;
5263
+ this._colorMap = ColorMaps_js_1.ColorMaps['eosb'];
5264
+ break;
5265
+ case 'cubehelix':
5266
+ this._colorMapIdx = 6;
5267
+ this._colorMap = ColorMaps_js_1.ColorMaps['cubehelix'];
5268
+ break;
5269
+ case 'hot':
5270
+ this._colorMapIdx = 7;
5271
+ this._colorMap = ColorMaps_js_1.ColorMaps['hot'];
5272
+ break;
5273
+ case 'gray':
5274
+ this._colorMapIdx = 8;
5275
+ this._colorMap = ColorMaps_js_1.ColorMaps['gray'];
5276
+ break;
5277
+ case 'native':
5278
+ this._colorMapIdx = 0;
5279
+ this._colorMap = ColorMaps_js_1.ColorMaps['native'];
5280
+ break;
5281
+ default:
5282
+ this._colorMapIdx = 9;
5283
+ this._colorMap = colorMap;
5284
+ }
5285
+ }
5286
+ initShaders() {
5287
+ this._xyzShaderProgram.enableProgram();
5288
+ }
5289
+ isLonLatGridVisible() {
5290
+ return this._latLonGrid.isVisible();
5291
+ }
5292
+ toggleLonLatGrid() {
5293
+ return this._latLonGrid.toggleShowGrid();
5294
+ }
5295
+ getFoV() {
5296
+ return this._latLonGrid.getFoV();
5297
+ }
5298
+ refresh(input) {
5299
+ const fov = this._latLonGrid.refreshFoV(input);
5300
+ // this._zoom = this.resolveVisibleZoom(fov)
5301
+ this._zoom = XYZFoVHelper_js_1.xyzFovHelper.getZoom(fov);
5302
+ }
5303
+ draw(input) {
5304
+ const vMatrix = input.camera.getCameraMatrix();
5305
+ if (!vMatrix)
5306
+ return;
5307
+ const pMatrix = input.pMatrix;
5308
+ if (!pMatrix)
5309
+ return;
5310
+ this.refresh(input);
5311
+ const mMatrix = this.getModelMatrix();
5312
+ this._xyzShaderProgram.setRuntimeColorMap(this._colorMap);
5313
+ const tileSelection = this._visibleTilesManager.computeVisibleTiles(this._zoom, this, this._webgl, input.camera, input.pMatrix);
5314
+ const visibleTiles = tileSelection.visibleTiles;
5315
+ const ancestorsMap = tileSelection.ancestorsMap;
5316
+ const tileKeys = this._tileBuffer.ensureTiles(this.getTilesToEnsure(visibleTiles, ancestorsMap), (coord) => this.createTile(coord));
5317
+ this._tileBuffer.evictCached(this._descriptor.maxCachedTiles);
5318
+ for (const tileKey of tileKeys) {
5319
+ const tile = this._tileBuffer.getActiveTile(tileKey);
5320
+ if (!tile || tile.coord.z !== tileSelection.currentZoom) {
5321
+ continue;
5322
+ }
5323
+ const drawn = tile.draw(pMatrix, vMatrix, mMatrix, this._colorMapIdx);
5324
+ if (drawn) {
5325
+ continue;
5326
+ }
5327
+ const ancestorTile = this.findBestAvailableAncestor(tile.coord);
5328
+ ancestorTile?.draw(tileSelection.currentZoom, [tile.coord], ancestorsMap, pMatrix, vMatrix, mMatrix, this._colorMapIdx);
5329
+ }
5330
+ this._latLonGrid.draw(input);
5331
+ }
5332
+ createTile(coord) {
5333
+ return new XYZAnchestorTile_js_1.XYZAnchestorTile(coord, this.resolveTileUrl(coord), this._webgl, this._xyzShaderProgram, this._meshBuilder, this._descriptor.segmentsPerSide);
5334
+ }
5335
+ getTilesToEnsure(visibleTiles, ancestorsMap) {
5336
+ const tilesByKey = new Map();
5337
+ for (const tile of visibleTiles) {
5338
+ tilesByKey.set(this.tileKey(tile), tile);
5339
+ }
5340
+ for (const ancestor of ancestorsMap.values()) {
5341
+ tilesByKey.set(this.tileKey(ancestor), ancestor);
5342
+ }
5343
+ return Array.from(tilesByKey.values());
5344
+ }
5345
+ findBestAvailableAncestor(targetTile) {
5346
+ for (let z = targetTile.z - 1; z >= 0; z--) {
5347
+ const dz = targetTile.z - z;
5348
+ const ancestorCoord = {
5349
+ z,
5350
+ x: targetTile.x >> dz,
5351
+ y: targetTile.y >> dz,
5352
+ };
5353
+ const ancestorTile = this._tileBuffer.getAnyTile(this.tileKey(ancestorCoord));
5354
+ if (ancestorTile?.ready) {
5355
+ return ancestorTile;
5356
+ }
5357
+ }
5358
+ return null;
5359
+ }
5360
+ resolveTileUrl(tile) {
5361
+ const urlResolver = this._descriptor.urlResolver;
5362
+ if (urlResolver) {
5363
+ return urlResolver(tile);
5364
+ }
5365
+ const dim = 2 ** tile.z;
5366
+ const y = this._descriptor.flipY ? dim - 1 - tile.y : tile.y;
5367
+ const subdomains = this._descriptor.subdomains;
5368
+ const subdomain = subdomains.length > 0
5369
+ ? subdomains[Math.abs(tile.x + tile.y + tile.z) % subdomains.length]
5370
+ : '';
5371
+ return this._baseurl
5372
+ .replace(/\{z\}/g, String(tile.z))
5373
+ .replace(/\{x\}/g, String(tile.x))
5374
+ .replace(/\{y\}/g, String(y))
5375
+ .replace(/\{s\}/g, subdomain ?? '');
5376
+ }
5377
+ getDebugStats() {
5378
+ const activeTiles = Array.from(this._tileBuffer.activeTiles.values(), (entry) => entry.tile);
5379
+ const cachedTiles = Array.from(this._tileBuffer.cachedTiles.values(), (entry) => entry.tile);
5380
+ const allTiles = [...activeTiles, ...cachedTiles];
5381
+ const selection = this._visibleTilesManager.selection;
5382
+ return {
5383
+ cacheSize: this._tileBuffer.size,
5384
+ visibleTileCount: selection.visibleTiles.length,
5385
+ currentTileCount: activeTiles.filter((tile) => tile.coord.z === selection.currentZoom).length,
5386
+ fallbackTileCount: selection.ancestorsMap.size,
5387
+ coreTileCount: selection.visibleTiles.length,
5388
+ coverageTileCount: selection.visibleTiles.length,
5389
+ readyTileCount: allTiles.filter((tile) => tile.ready).length,
5390
+ loadingTileCount: allTiles.filter((tile) => tile.loading).length,
5391
+ coolingDownTileCount: 0,
5392
+ currentZoom: selection.currentZoom,
5393
+ tileSelectionKey: selection.key,
5394
+ isSettling: false,
5395
+ coarseTileCount: selection.ancestorsMap.size,
5396
+ hasPendingSelection: false,
5397
+ pendingSelectionKey: null,
5398
+ };
5399
+ }
5400
+ tileKey(tile) {
5401
+ return `${tile.z}/${tile.x}/${tile.y}`;
5402
+ }
5403
+ }
5404
+ exports.XYZMap = XYZMap;
5405
+
5406
+
5407
+ /***/ }),
5408
+
5409
+ /***/ 1961:
5410
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
5411
+
5412
+ // ESM COMPAT FLAG
5413
+ __webpack_require__.r(__webpack_exports__);
5414
+
5415
+ // EXPORTS
5416
+ __webpack_require__.d(__webpack_exports__, {
5417
+ glMatrix: () => (/* reexport */ common_namespaceObject),
5418
+ mat2: () => (/* reexport */ mat2_namespaceObject),
5419
+ mat2d: () => (/* reexport */ mat2d_namespaceObject),
5420
+ mat3: () => (/* reexport */ mat3_namespaceObject),
5421
+ mat4: () => (/* reexport */ mat4_namespaceObject),
5422
+ quat: () => (/* reexport */ quat_namespaceObject),
5423
+ quat2: () => (/* reexport */ quat2_namespaceObject),
5424
+ vec2: () => (/* reexport */ vec2_namespaceObject),
5425
+ vec3: () => (/* reexport */ vec3_namespaceObject),
5426
+ vec4: () => (/* reexport */ vec4_namespaceObject)
5427
+ });
5428
+
5429
+ // NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/common.js
5430
+ var common_namespaceObject = {};
5431
+ __webpack_require__.r(common_namespaceObject);
5432
+ __webpack_require__.d(common_namespaceObject, {
5433
+ ANGLE_ORDER: () => (ANGLE_ORDER),
5434
+ ARRAY_TYPE: () => (ARRAY_TYPE),
5435
+ EPSILON: () => (EPSILON),
5436
+ RANDOM: () => (RANDOM),
5437
+ equals: () => (equals),
5438
+ round: () => (round),
5439
+ setMatrixArrayType: () => (setMatrixArrayType),
5440
+ toDegree: () => (toDegree),
5441
+ toRadian: () => (toRadian)
5442
+ });
5443
+
5444
+ // NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat2.js
5445
+ var mat2_namespaceObject = {};
5446
+ __webpack_require__.r(mat2_namespaceObject);
5447
+ __webpack_require__.d(mat2_namespaceObject, {
5448
+ LDU: () => (LDU),
5449
+ add: () => (add),
5450
+ adjoint: () => (adjoint),
5451
+ clone: () => (clone),
5452
+ copy: () => (copy),
5453
+ create: () => (create),
5454
+ determinant: () => (determinant),
5455
+ equals: () => (mat2_equals),
5456
+ exactEquals: () => (exactEquals),
5457
+ frob: () => (frob),
5458
+ fromRotation: () => (fromRotation),
5459
+ fromScaling: () => (fromScaling),
5460
+ fromValues: () => (fromValues),
5461
+ identity: () => (identity),
5462
+ invert: () => (invert),
5463
+ mul: () => (mul),
5464
+ multiply: () => (multiply),
5465
+ multiplyScalar: () => (multiplyScalar),
5466
+ multiplyScalarAndAdd: () => (multiplyScalarAndAdd),
5467
+ rotate: () => (rotate),
5468
+ scale: () => (scale),
5469
+ set: () => (set),
5470
+ str: () => (str),
5471
+ sub: () => (sub),
5472
+ subtract: () => (subtract),
5473
+ transpose: () => (transpose)
5474
+ });
5475
+
5476
+ // NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat2d.js
5477
+ var mat2d_namespaceObject = {};
5478
+ __webpack_require__.r(mat2d_namespaceObject);
5479
+ __webpack_require__.d(mat2d_namespaceObject, {
5480
+ add: () => (mat2d_add),
5481
+ clone: () => (mat2d_clone),
5081
5482
  copy: () => (mat2d_copy),
5082
5483
  create: () => (mat2d_create),
5083
5484
  determinant: () => (mat2d_determinant),
@@ -12839,6 +13240,18 @@ var vec2_forEach = function () {
12839
13240
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
12840
13241
 
12841
13242
 
13243
+ /*
13244
+ * AstroViewer
13245
+ * Copyright (C) Fabrizio Giordano
13246
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
13247
+ *
13248
+ * This file is part of AstroViewer.
13249
+ * AstroViewer is distributed under a dual-license model.
13250
+ * Commercial use requires a separate commercial license.
13251
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
13252
+ *
13253
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
13254
+ */
12842
13255
  var __importDefault = (this && this.__importDefault) || function (mod) {
12843
13256
  return (mod && mod.__esModule) ? mod : { "default": mod };
12844
13257
  };
@@ -13008,203 +13421,236 @@ exports.VisibleTilesManager = VisibleTilesManager;
13008
13421
 
13009
13422
  /***/ }),
13010
13423
 
13011
- /***/ 2330:
13012
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
13424
+ /***/ 2166:
13425
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
13013
13426
 
13427
+ /*
13428
+ * AstroViewer
13429
+ * Copyright (C) Fabrizio Giordano
13430
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
13431
+ *
13432
+ * This file is part of AstroViewer.
13433
+ * AstroViewer is distributed under a dual-license model.
13434
+ * Commercial use requires a separate commercial license.
13435
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
13436
+ *
13437
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
13438
+ */
13439
+ /**
13440
+ * Ray picking helpers for XYZ/WebMercator maps.
13441
+ *
13442
+ * Unlike RayPickingUtils, this module has no HEALPix dependency. It intersects
13443
+ * screen rays with an XYZ sphere, converts the hit to lon/lat, then maps that
13444
+ * position to XYZ z/x/y tile coordinates.
13445
+ */
13014
13446
 
13015
- var __importDefault = (this && this.__importDefault) || function (mod) {
13016
- return (mod && mod.__esModule) ? mod : { "default": mod };
13017
- };
13018
13447
  Object.defineProperty(exports, "__esModule", ({ value: true }));
13019
- exports.XYZTileProvider = void 0;
13020
- const Global_js_1 = __importDefault(__webpack_require__(4382));
13448
+ const gl_matrix_1 = __webpack_require__(1961);
13021
13449
  const MAX_MERCATOR_LAT = 85.0511287798066;
13022
- class XYZTileProvider {
13023
- _config;
13024
- constructor(config) {
13025
- this._config = config;
13026
- }
13027
- get config() {
13028
- return this._config;
13029
- }
13030
- get minZoom() {
13031
- return Math.max(0, Math.floor(this._config.minZoom ?? 0));
13032
- }
13033
- get maxZoom() {
13034
- return Math.max(this.minZoom, Math.floor(this._config.maxZoom ?? 6));
13035
- }
13036
- getInitialTiles() {
13037
- return this.getVisibleTilesAtZoom(1, null, [], [], 1);
13450
+ class XYZRayPickingUtils {
13451
+ static getRayFromMouse(mouseX, mouseY, pMatrix, webgl, vMatrix) {
13452
+ const gl = webgl;
13453
+ const canvas = gl.canvas;
13454
+ const rect = canvas.getBoundingClientRect();
13455
+ const x = (2.0 * mouseX) / rect.width - 1.0;
13456
+ const y = 1.0 - (2.0 * mouseY) / rect.height;
13457
+ const rayClip = [x, y, -1.0, 1.0];
13458
+ const pInv = gl_matrix_1.mat4.create();
13459
+ gl_matrix_1.mat4.invert(pInv, pMatrix);
13460
+ const rayEye4 = [0, 0, 0, 0];
13461
+ XYZRayPickingUtils.mat4MultiplyVec4(pInv, rayClip, rayEye4);
13462
+ const rayEye = [rayEye4[0], rayEye4[1], -1.0, 0.0];
13463
+ const vInv = gl_matrix_1.mat4.create();
13464
+ gl_matrix_1.mat4.invert(vInv, vMatrix);
13465
+ const rayWorld4 = [0, 0, 0, 0];
13466
+ XYZRayPickingUtils.mat4MultiplyVec4(vInv, rayEye, rayWorld4);
13467
+ const rayWorld = gl_matrix_1.vec3.fromValues(rayWorld4[0], rayWorld4[1], rayWorld4[2]);
13468
+ gl_matrix_1.vec3.normalize(rayWorld, rayWorld);
13469
+ return rayWorld;
13038
13470
  }
13039
- getTileUrl(tile) {
13040
- if (this._config.urlResolver) {
13041
- return this._config.urlResolver(tile);
13471
+ static raySphere(rayOrigWorld, rayDirectionWorld, sphere) {
13472
+ let intersectionDistance = -1;
13473
+ const L = gl_matrix_1.vec3.create();
13474
+ gl_matrix_1.vec3.subtract(L, rayOrigWorld, sphere.center);
13475
+ const b = gl_matrix_1.vec3.dot(rayDirectionWorld, L);
13476
+ const c = gl_matrix_1.vec3.dot(L, L) - sphere.radius * sphere.radius;
13477
+ const disc = b * b - c;
13478
+ if (disc > 0.0) {
13479
+ const s = Math.sqrt(disc);
13480
+ const ta = -b + s;
13481
+ const tb = -b - s;
13482
+ if (ta >= 0.0 || tb >= 0.0) {
13483
+ intersectionDistance = tb < 0.0 ? ta : Math.min(ta, tb);
13484
+ }
13042
13485
  }
13043
- const effectiveY = this.getEffectiveTileY(tile);
13044
- const subdomain = this.getSubdomain(tile);
13045
- return this._config.urlTemplate
13046
- .replace(/\{z\}/g, String(tile.z))
13047
- .replace(/\{x\}/g, String(tile.x))
13048
- .replace(/\{y\}/g, String(effectiveY))
13049
- .replace(/\{s\}/g, subdomain);
13050
- }
13051
- resolveZoom(fovDeg) {
13052
- const safeFov = Math.max(0.01, Math.min(180, fovDeg));
13053
- const targetTileWidthDeg = Math.max(0.01, safeFov / 2);
13054
- const rawZoom = Math.ceil(Math.log2(360 / targetTileWidthDeg));
13055
- return this.clampZoom(rawZoom);
13056
- }
13057
- clampZoom(zoom) {
13058
- return Math.max(this.minZoom, Math.min(this.maxZoom, zoom));
13059
- }
13060
- getEffectiveTileY(tile) {
13061
- if (!this._config.flipY) {
13062
- return tile.y;
13486
+ else if (disc === 0.0) {
13487
+ const t = -b;
13488
+ if (t >= 0.0) {
13489
+ intersectionDistance = t;
13490
+ }
13063
13491
  }
13064
- const dim = 2 ** tile.z;
13065
- return dim - 1 - tile.y;
13492
+ return intersectionDistance;
13066
13493
  }
13067
- getSubdomain(tile) {
13068
- const subdomains = this._config.subdomains ?? [];
13069
- if (subdomains.length === 0) {
13070
- return '';
13494
+ static getIntersectionPointWithModel(mouseX, mouseY, xyzModel, webgl, camera, pMatrix) {
13495
+ const vMatrix = camera.getCameraMatrix();
13496
+ const rayWorld = XYZRayPickingUtils.getRayFromMouse(mouseX, mouseY, pMatrix, webgl, vMatrix);
13497
+ const t = XYZRayPickingUtils.raySphere(camera.getCameraPosition(), rayWorld, xyzModel);
13498
+ if (t < 0) {
13499
+ return null;
13500
+ }
13501
+ const worldHit = gl_matrix_1.vec3.create();
13502
+ gl_matrix_1.vec3.scale(worldHit, rayWorld, t);
13503
+ gl_matrix_1.vec3.add(worldHit, camera.getCameraPosition(), worldHit);
13504
+ const worldHit4 = [worldHit[0], worldHit[1], worldHit[2], 1.0];
13505
+ const modelHit4 = [0, 0, 0, 0];
13506
+ XYZRayPickingUtils.mat4MultiplyVec4(xyzModel.getModelMatrixInverse(), worldHit4, modelHit4);
13507
+ return [modelHit4[0], modelHit4[1], modelHit4[2]];
13508
+ }
13509
+ static getLonLatFromMouse(mouseX, mouseY, xyzModel, webgl, camera, pMatrix) {
13510
+ const hit = XYZRayPickingUtils.getIntersectionPointWithModel(mouseX, mouseY, xyzModel, webgl, camera, pMatrix);
13511
+ return hit ? XYZRayPickingUtils.modelPointToLonLat(hit) : null;
13512
+ }
13513
+ static getTileFromMouse(mouseX, mouseY, z, xyzModel, webgl, camera, pMatrix) {
13514
+ const lonLat = XYZRayPickingUtils.getLonLatFromMouse(mouseX, mouseY, xyzModel, webgl, camera, pMatrix);
13515
+ if (!lonLat || !XYZRayPickingUtils.isMercatorLatitude(lonLat.latDeg)) {
13516
+ return null;
13071
13517
  }
13072
- const index = Math.abs(tile.x + tile.y + tile.z) % subdomains.length;
13073
- return subdomains[index] ?? '';
13518
+ return XYZRayPickingUtils.lonLatToTile(lonLat.lonDeg, lonLat.latDeg, z);
13074
13519
  }
13075
- getVisibleTilesAtZoom(z, centerSphericalDeg, fovPolygon, viewportSphericalSamples, padding = 1) {
13076
- const dim = 2 ** z;
13077
- const center = this.resolveViewCenter(null, centerSphericalDeg);
13078
- const normalizedCenterLon = this.normalizeLonAround(center.lonDeg, center.lonDeg);
13079
- const polygonPoints = fovPolygon.length > 0
13080
- ? fovPolygon.map((point) => ({
13081
- lonDeg: this.normalizeLonAround(point.raDeg > 180 ? point.raDeg - 360 : point.raDeg, normalizedCenterLon),
13082
- latDeg: point.decDeg,
13083
- }))
13084
- : [center];
13085
- const samplePoints = viewportSphericalSamples.map((sample) => ({
13086
- lonDeg: this.normalizeLonAround(sample.phi > 180 ? sample.phi - 360 : sample.phi, normalizedCenterLon),
13087
- latDeg: 90 - sample.theta,
13088
- }));
13089
- const coveragePoints = [center, ...polygonPoints, ...samplePoints];
13090
- let minLon = normalizedCenterLon;
13091
- let maxLon = normalizedCenterLon;
13092
- let minLat = center.latDeg;
13093
- let maxLat = center.latDeg;
13094
- for (const point of coveragePoints) {
13095
- minLon = Math.min(minLon, point.lonDeg);
13096
- maxLon = Math.max(maxLon, point.lonDeg);
13097
- minLat = Math.min(minLat, point.latDeg);
13098
- maxLat = Math.max(maxLat, point.latDeg);
13099
- }
13100
- const adaptivePadding = Math.max(padding, Math.min(3, Math.max(1, Math.ceil(z / 3))));
13101
- const minX = Math.floor(((minLon + 180) / 360) * dim) - adaptivePadding;
13102
- const maxX = Math.floor(((maxLon + 180) / 360) * dim) + adaptivePadding;
13103
- const minY = Math.floor(this.latToTileY(maxLat, z)) - adaptivePadding;
13104
- const maxY = Math.floor(this.latToTileY(minLat, z)) + adaptivePadding;
13520
+ static getVisibleTilesFromViewport(z, xyzModel, webgl, camera, pMatrix, sampleCount = 9, padding = 2) {
13521
+ const gl = webgl;
13522
+ const canvas = gl.canvas;
13523
+ const rect = canvas.getBoundingClientRect();
13524
+ const samples = Math.max(2, Math.floor(sampleCount));
13525
+ const edgeSamples = Math.max(samples * 2 + 1, 21);
13526
+ const safePadding = Math.max(0, Math.floor(padding));
13105
13527
  const tiles = [];
13106
- for (let x = minX; x <= maxX; x++) {
13107
- for (let y = minY; y <= maxY; y++) {
13108
- tiles.push({
13109
- z,
13110
- x: this.wrapTileX(x, dim),
13111
- y: this.clampTileY(y, dim),
13112
- });
13528
+ const addSample = (x, y) => {
13529
+ const tile = XYZRayPickingUtils.getTileFromMouse(x, y, z, xyzModel, webgl, camera, pMatrix);
13530
+ if (!tile)
13531
+ return;
13532
+ tiles.push(tile);
13533
+ tiles.push(...XYZRayPickingUtils.getNeighborTiles(tile, safePadding));
13534
+ };
13535
+ for (let iy = 0; iy < samples; iy++) {
13536
+ const y = samples === 1 ? rect.height / 2 : (iy / (samples - 1)) * rect.height;
13537
+ for (let ix = 0; ix < samples; ix++) {
13538
+ const x = samples === 1 ? rect.width / 2 : (ix / (samples - 1)) * rect.width;
13539
+ addSample(x, y);
13113
13540
  }
13114
13541
  }
13115
- for (const point of coveragePoints) {
13116
- const centerTileX = Math.floor(((point.lonDeg + 180) / 360) * dim);
13117
- const centerTileY = Math.floor(this.latToTileY(point.latDeg, z));
13118
- for (let dx = -adaptivePadding; dx <= adaptivePadding; dx++) {
13119
- for (let dy = -adaptivePadding; dy <= adaptivePadding; dy++) {
13120
- tiles.push({
13121
- z,
13122
- x: this.wrapTileX(centerTileX + dx, dim),
13123
- y: this.clampTileY(centerTileY + dy, dim),
13124
- });
13125
- }
13126
- }
13542
+ for (let i = 0; i < edgeSamples; i++) {
13543
+ const t = edgeSamples === 1 ? 0.5 : i / (edgeSamples - 1);
13544
+ const x = t * rect.width;
13545
+ const y = t * rect.height;
13546
+ addSample(x, 0);
13547
+ addSample(x, rect.height);
13548
+ addSample(0, y);
13549
+ addSample(rect.width, y);
13550
+ }
13551
+ return XYZRayPickingUtils.fillSmallTileGaps(XYZRayPickingUtils.deduplicateTiles(tiles));
13552
+ }
13553
+ static modelPointToLonLat(point) {
13554
+ const [x, y, z] = point;
13555
+ const len = Math.hypot(x, y, z);
13556
+ if (!Number.isFinite(len) || len === 0) {
13557
+ return { lonDeg: 0, latDeg: 0 };
13127
13558
  }
13128
- return this.deduplicateTiles(tiles);
13559
+ const lonDeg = (Math.atan2(y, x) * 180) / Math.PI;
13560
+ const latDeg = (Math.asin(Math.max(-1, Math.min(1, z / len))) * 180) / Math.PI;
13561
+ return { lonDeg, latDeg };
13129
13562
  }
13130
- tileFromSpherical(zoom, sphericalDeg) {
13131
- const lonDeg = sphericalDeg.phi > 180 ? sphericalDeg.phi - 360 : sphericalDeg.phi;
13132
- const latDeg = 90 - sphericalDeg.theta;
13563
+ static lonLatToTile(lonDeg, latDeg, z) {
13564
+ const zoom = Math.max(0, Math.floor(z));
13133
13565
  const dim = 2 ** zoom;
13134
13566
  const x = Math.floor(((lonDeg + 180) / 360) * dim);
13135
- const y = Math.floor(this.latToTileY(latDeg, zoom));
13567
+ const y = Math.floor(XYZRayPickingUtils.latToTileY(latDeg, zoom));
13136
13568
  return {
13137
13569
  z: zoom,
13138
- x: this.wrapTileX(x, dim),
13139
- y: this.clampTileY(y, dim),
13570
+ x: XYZRayPickingUtils.wrapTileX(x, dim),
13571
+ y: XYZRayPickingUtils.clampTileY(y, dim),
13140
13572
  };
13141
13573
  }
13142
- getNeighborTiles(tile, ring = 1) {
13574
+ static getNeighborTiles(tile, ring = 1) {
13143
13575
  const dim = 2 ** tile.z;
13144
- const neighbors = [];
13145
- for (let dx = -ring; dx <= ring; dx++) {
13146
- for (let dy = -ring; dy <= ring; dy++) {
13147
- neighbors.push({
13576
+ const tiles = [];
13577
+ const safeRing = Math.max(0, Math.floor(ring));
13578
+ for (let dx = -safeRing; dx <= safeRing; dx++) {
13579
+ for (let dy = -safeRing; dy <= safeRing; dy++) {
13580
+ tiles.push({
13148
13581
  z: tile.z,
13149
- x: this.wrapTileX(tile.x + dx, dim),
13150
- y: this.clampTileY(tile.y + dy, dim),
13582
+ x: XYZRayPickingUtils.wrapTileX(tile.x + dx, dim),
13583
+ y: XYZRayPickingUtils.clampTileY(tile.y + dy, dim),
13151
13584
  });
13152
13585
  }
13153
13586
  }
13154
- return this.deduplicateTiles(neighbors);
13587
+ return XYZRayPickingUtils.deduplicateTiles(tiles);
13155
13588
  }
13156
- deduplicateTiles(tiles) {
13157
- const unique = new Map();
13589
+ static deduplicateTiles(tiles) {
13590
+ const map = new Map();
13158
13591
  for (const tile of tiles) {
13159
- unique.set(`${tile.z}/${tile.x}/${tile.y}`, tile);
13592
+ map.set(`${tile.z}/${tile.x}/${tile.y}`, tile);
13160
13593
  }
13161
- return Array.from(unique.values());
13594
+ return Array.from(map.values());
13162
13595
  }
13163
- resolveViewCenter(camera, centerSphericalDeg) {
13164
- if (centerSphericalDeg) {
13165
- return {
13166
- lonDeg: centerSphericalDeg.phi > 180 ? centerSphericalDeg.phi - 360 : centerSphericalDeg.phi,
13167
- latDeg: 90 - centerSphericalDeg.theta,
13168
- };
13596
+ static fillSmallTileGaps(tiles) {
13597
+ if (tiles.length === 0) {
13598
+ return tiles;
13169
13599
  }
13170
- if (!camera) {
13171
- return { lonDeg: 0, latDeg: 0 };
13600
+ const zoom = tiles[0].z;
13601
+ const dim = 2 ** zoom;
13602
+ const map = new Map();
13603
+ const key = (tile) => `${tile.z}/${tile.x}/${tile.y}`;
13604
+ const add = (tile) => {
13605
+ map.set(key(tile), tile);
13606
+ };
13607
+ const has = (x, y) => (y >= 0 && y < dim && map.has(`${zoom}/${XYZRayPickingUtils.wrapTileX(x, dim)}/${y}`));
13608
+ for (const tile of tiles) {
13609
+ add(tile);
13172
13610
  }
13173
- const [x, y, z] = camera.getCameraPosition();
13174
- const len = Math.hypot(x, y, z);
13175
- if (!Number.isFinite(len) || len === 0) {
13176
- return { lonDeg: 0, latDeg: 0 };
13611
+ for (const tile of tiles) {
13612
+ const x = tile.x;
13613
+ const y = tile.y;
13614
+ if (has(x - 2, y) && !has(x - 1, y)) {
13615
+ add({ z: zoom, x: XYZRayPickingUtils.wrapTileX(x - 1, dim), y });
13616
+ }
13617
+ if (has(x + 2, y) && !has(x + 1, y)) {
13618
+ add({ z: zoom, x: XYZRayPickingUtils.wrapTileX(x + 1, dim), y });
13619
+ }
13620
+ if (has(x, y - 2) && !has(x, y - 1)) {
13621
+ add({ z: zoom, x, y: y - 1 });
13622
+ }
13623
+ if (has(x, y + 2) && !has(x, y + 1)) {
13624
+ add({ z: zoom, x, y: y + 1 });
13625
+ }
13177
13626
  }
13178
- const scale = Global_js_1.default.insideSphere ? 1 / len : -1 / len;
13179
- const vx = x * scale;
13180
- const vy = y * scale;
13181
- const vz = z * scale;
13182
- const lonDeg = (Math.atan2(vy, vx) * 180) / Math.PI;
13183
- const latDeg = (Math.asin(Math.max(-1, Math.min(1, vz))) * 180) / Math.PI;
13184
- return { lonDeg, latDeg };
13627
+ return Array.from(map.values());
13185
13628
  }
13186
- latToTileY(latDeg, z) {
13629
+ static latToTileY(latDeg, z) {
13187
13630
  const lat = Math.max(-MAX_MERCATOR_LAT, Math.min(MAX_MERCATOR_LAT, latDeg));
13188
13631
  const latRad = (lat * Math.PI) / 180;
13189
- const n = 2 ** z;
13190
- return ((1 - Math.asinh(Math.tan(latRad)) / Math.PI) / 2) * n;
13632
+ const dim = 2 ** z;
13633
+ return ((1 - Math.asinh(Math.tan(latRad)) / Math.PI) / 2) * dim;
13191
13634
  }
13192
- wrapTileX(x, dim) {
13193
- return ((x % dim) + dim) % dim;
13635
+ static isMercatorLatitude(latDeg) {
13636
+ return Math.abs(latDeg) <= MAX_MERCATOR_LAT;
13194
13637
  }
13195
- normalizeLonAround(lonDeg, referenceLonDeg) {
13196
- let lon = lonDeg;
13197
- while (lon - referenceLonDeg > 180)
13198
- lon -= 360;
13199
- while (lon - referenceLonDeg < -180)
13200
- lon += 360;
13201
- return lon;
13638
+ static wrapTileX(x, dim) {
13639
+ return ((x % dim) + dim) % dim;
13202
13640
  }
13203
- clampTileY(y, dim) {
13641
+ static clampTileY(y, dim) {
13204
13642
  return Math.max(0, Math.min(dim - 1, y));
13205
13643
  }
13644
+ static mat4MultiplyVec4(a, b, out) {
13645
+ const d = b[0], e = b[1], g = b[2], w = b[3];
13646
+ out[0] = a[0] * d + a[4] * e + a[8] * g + a[12] * w;
13647
+ out[1] = a[1] * d + a[5] * e + a[9] * g + a[13] * w;
13648
+ out[2] = a[2] * d + a[6] * e + a[10] * g + a[14] * w;
13649
+ out[3] = a[3] * d + a[7] * e + a[11] * g + a[15] * w;
13650
+ return out;
13651
+ }
13206
13652
  }
13207
- exports.XYZTileProvider = XYZTileProvider;
13653
+ exports["default"] = XYZRayPickingUtils;
13208
13654
 
13209
13655
 
13210
13656
  /***/ }),
@@ -13212,6 +13658,18 @@ exports.XYZTileProvider = XYZTileProvider;
13212
13658
  /***/ 2368:
13213
13659
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
13214
13660
 
13661
+ /*
13662
+ * AstroViewer
13663
+ * Copyright (C) Fabrizio Giordano
13664
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
13665
+ *
13666
+ * This file is part of AstroViewer.
13667
+ * AstroViewer is distributed under a dual-license model.
13668
+ * Commercial use requires a separate commercial license.
13669
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
13670
+ *
13671
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
13672
+ */
13215
13673
 
13216
13674
  var __importDefault = (this && this.__importDefault) || function (mod) {
13217
13675
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -13455,6 +13913,18 @@ exports["default"] = AllSky;
13455
13913
  /***/ 2475:
13456
13914
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
13457
13915
 
13916
+ /*
13917
+ * AstroViewer
13918
+ * Copyright (C) Fabrizio Giordano
13919
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
13920
+ *
13921
+ * This file is part of AstroViewer.
13922
+ * AstroViewer is distributed under a dual-license model.
13923
+ * Commercial use requires a separate commercial license.
13924
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
13925
+ *
13926
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
13927
+ */
13458
13928
 
13459
13929
  var __importDefault = (this && this.__importDefault) || function (mod) {
13460
13930
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -13566,273 +14036,38 @@ class Footprint {
13566
14036
  exports.Footprint = Footprint;
13567
14037
 
13568
14038
 
13569
- /***/ }),
13570
-
13571
- /***/ 2502:
13572
- /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
13573
-
13574
-
13575
- Object.defineProperty(exports, "__esModule", ({ value: true }));
13576
- exports.XYZLayer = void 0;
13577
- const AbstractSkyEntity_js_1 = __webpack_require__(4735);
13578
- const XYZShaderProgram_js_1 = __webpack_require__(149);
13579
- const XYZAncestorMeshCache_js_1 = __webpack_require__(497);
13580
- const XYZMeshBuilder_js_1 = __webpack_require__(8819);
13581
- const XYZTileBuffer_js_1 = __webpack_require__(2737);
13582
- const XYZTileProvider_js_1 = __webpack_require__(2330);
13583
- const XYZVisibleTilesManager_js_1 = __webpack_require__(6937);
13584
- class XYZLayer extends AbstractSkyEntity_js_1.AbstractSkyEntity {
13585
- static DEFAULT_MAX_CACHED_TILES = 384;
13586
- _config;
13587
- _provider;
13588
- _visibleTilesManager;
13589
- _meshBuilder;
13590
- _xyzShaderProgram;
13591
- _tileBuffer;
13592
- _ancestorMeshCache;
13593
- _visibleTileKeys = [];
13594
- _fallbackVisibleTileKeys = [];
13595
- _baseVisibleTileKeys = [];
13596
- _tilePriorities = new Map();
13597
- _tileSelectionKey = null;
13598
- _currentTileCount = 0;
13599
- _fallbackTileCount = 0;
13600
- _coreTileCount = 0;
13601
- _coverageTileCount = 0;
13602
- constructor(config, webgl) {
13603
- super(1, [0, 0, 0], 0, 0, 'XYZ Earth Layer', webgl, false);
13604
- this._config = config;
13605
- this._provider = new XYZTileProvider_js_1.XYZTileProvider(config);
13606
- this._visibleTilesManager = new XYZVisibleTilesManager_js_1.XYZVisibleTilesManager(this._provider);
13607
- this._meshBuilder = new XYZMeshBuilder_js_1.XYZMeshBuilder();
13608
- this._xyzShaderProgram = new XYZShaderProgram_js_1.XYZShaderProgram(webgl);
13609
- this._tileBuffer = new XYZTileBuffer_js_1.XYZTileBuffer(1, webgl, this._meshBuilder, this._xyzShaderProgram);
13610
- this._ancestorMeshCache = new XYZAncestorMeshCache_js_1.XYZAncestorMeshCache(webgl, this._meshBuilder);
13611
- this.initGL(webgl);
13612
- this.bootstrapTiles(180, null, null);
13613
- }
13614
- get config() {
13615
- return this._config;
13616
- }
13617
- getDebugStats() {
13618
- let readyTileCount = 0;
13619
- let loadingTileCount = 0;
13620
- let coolingDownTileCount = 0;
13621
- const now = Date.now();
13622
- const allTiles = [
13623
- ...Array.from(this._tileBuffer.activeTiles.values(), (entry) => entry.tile),
13624
- ...Array.from(this._tileBuffer.cachedTiles.values(), (entry) => entry.tile),
13625
- ];
13626
- for (const tile of allTiles) {
13627
- if (tile.ready) {
13628
- readyTileCount += 1;
13629
- }
13630
- if (tile.loading) {
13631
- loadingTileCount += 1;
13632
- }
13633
- if (tile.failedUntil > now) {
13634
- coolingDownTileCount += 1;
13635
- }
13636
- }
13637
- const currentZoom = this._visibleTileKeys.reduce((maxZoom, tileKey) => {
13638
- const zoom = Number.parseInt(tileKey.split('/')[0] ?? '', 10);
13639
- if (!Number.isFinite(zoom)) {
13640
- return maxZoom;
13641
- }
13642
- return maxZoom == null ? zoom : Math.max(maxZoom, zoom);
13643
- }, null);
13644
- return {
13645
- cacheSize: this._tileBuffer.size,
13646
- visibleTileCount: this._visibleTileKeys.length,
13647
- currentTileCount: this._currentTileCount,
13648
- fallbackTileCount: this._fallbackTileCount,
13649
- coreTileCount: this._coreTileCount,
13650
- coverageTileCount: this._coverageTileCount,
13651
- readyTileCount,
13652
- loadingTileCount,
13653
- coolingDownTileCount,
13654
- currentZoom,
13655
- tileSelectionKey: this._tileSelectionKey,
13656
- isSettling: false,
13657
- coarseTileCount: 0,
13658
- hasPendingSelection: false,
13659
- pendingSelectionKey: null,
13660
- };
13661
- }
13662
- bootstrapTiles(fovDeg, camera, centerSphericalDeg, fovPolygon = null, viewportSphericalSamples = null) {
13663
- const selection = camera
13664
- ? this._visibleTilesManager.selectTiles({
13665
- fovDeg,
13666
- camera,
13667
- pMatrix: new Float32Array(),
13668
- centerSphericalDeg: centerSphericalDeg ?? undefined,
13669
- fovPolygon: fovPolygon ?? undefined,
13670
- viewportSphericalSamples: viewportSphericalSamples ?? undefined,
13671
- })
13672
- : {
13673
- key: 'initial',
13674
- currentTiles: this._provider.getInitialTiles(),
13675
- fallbackTiles: [],
13676
- currentZoom: 1,
13677
- coreTileCount: this._provider.getInitialTiles().length,
13678
- coverageTileCount: 0,
13679
- };
13680
- if (selection.key === this._tileSelectionKey) {
13681
- return;
13682
- }
13683
- this._tileSelectionKey = selection.key;
13684
- this._currentTileCount = selection.currentTiles.length;
13685
- this._fallbackTileCount = selection.fallbackTiles.length;
13686
- this._coreTileCount = selection.coreTileCount;
13687
- this._coverageTileCount = selection.coverageTileCount;
13688
- const segments = this._config.segmentsPerSide ?? 16;
13689
- const baseTiles = this._provider.getInitialTiles();
13690
- const coreTileKeys = new Set(selection.currentTiles
13691
- .slice(0, selection.coreTileCount)
13692
- .map((tileCoord) => this.getTileKey(tileCoord)));
13693
- const baseTileKeys = new Set(baseTiles.map((tileCoord) => this.getTileKey(tileCoord)));
13694
- const prioritizedBaseTiles = baseTiles.map((tileCoord, index) => ({
13695
- tileCoord,
13696
- priority: 5000 + (baseTiles.length - index),
13697
- role: 'base',
13698
- }));
13699
- const prioritizedCurrentTiles = selection.currentTiles.map((tileCoord, index) => ({
13700
- tileCoord,
13701
- priority: 10000 + (selection.currentTiles.length - index),
13702
- role: coreTileKeys.has(this.getTileKey(tileCoord)) ? 'current' : 'coverage',
13703
- }));
13704
- const prioritizedFallbackTiles = selection.fallbackTiles.map((tileCoord, index) => ({
13705
- tileCoord,
13706
- priority: 1000 + (selection.fallbackTiles.length - index),
13707
- role: 'fallback',
13708
- }));
13709
- const requestedTiles = [...prioritizedBaseTiles, ...prioritizedCurrentTiles, ...prioritizedFallbackTiles];
13710
- this._tilePriorities.clear();
13711
- this._fallbackVisibleTileKeys = [];
13712
- this._baseVisibleTileKeys = [];
13713
- const orderedRequests = requestedTiles
13714
- .sort((a, b) => a.tileCoord.z - b.tileCoord.z)
13715
- .map(({ tileCoord, priority, role }) => {
13716
- const tileKey = this.getTileKey(tileCoord);
13717
- this._tilePriorities.set(tileKey, priority);
13718
- return {
13719
- tileCoord,
13720
- priority,
13721
- url: this._provider.getTileUrl(tileCoord),
13722
- role,
13723
- };
13724
- });
13725
- const ensuredKeys = this._tileBuffer.ensureTiles(orderedRequests, segments);
13726
- const fallbackKeySet = new Set(selection.fallbackTiles.map((tileCoord) => this.getTileKey(tileCoord)));
13727
- this._baseVisibleTileKeys = ensuredKeys.filter((tileKey) => baseTileKeys.has(tileKey));
13728
- this._fallbackVisibleTileKeys = ensuredKeys.filter((tileKey) => fallbackKeySet.has(tileKey) && !baseTileKeys.has(tileKey));
13729
- this._visibleTileKeys = ensuredKeys.filter((tileKey) => !fallbackKeySet.has(tileKey) && !baseTileKeys.has(tileKey));
13730
- this.evictCache();
13731
- }
13732
- draw(input) {
13733
- const vMatrix = input.camera.getCameraMatrix();
13734
- if (!vMatrix)
13735
- return;
13736
- this.bootstrapTiles(input.fovDeg ?? 180, input.camera, input.centerSphericalDeg ?? null, input.fovPolygon ?? null, input.viewportSphericalSamples ?? null);
13737
- const pMatrix = input.pMatrix;
13738
- const mMatrix = this.getModelMatrix();
13739
- for (const tileKey of this._baseVisibleTileKeys) {
13740
- const tile = this._tileBuffer.getActiveTile(tileKey);
13741
- if (!tile)
13742
- continue;
13743
- tile.draw(pMatrix, vMatrix, mMatrix, this._tilePriorities.get(tileKey) ?? 0);
13744
- }
13745
- for (const tileKey of this._fallbackVisibleTileKeys) {
13746
- const tile = this._tileBuffer.getActiveTile(tileKey);
13747
- if (!tile)
13748
- continue;
13749
- tile.draw(pMatrix, vMatrix, mMatrix, this._tilePriorities.get(tileKey) ?? 0, false);
13750
- }
13751
- for (const tileKey of this._visibleTileKeys) {
13752
- const tile = this._tileBuffer.getActiveTile(tileKey);
13753
- if (tile?.ready) {
13754
- tile.draw(pMatrix, vMatrix, mMatrix, this._tilePriorities.get(tileKey) ?? 0);
13755
- continue;
13756
- }
13757
- const targetCoord = this.parseTileKey(tileKey);
13758
- if (targetCoord) {
13759
- const ancestorTile = this.findBestAvailableAncestor(targetCoord);
13760
- if (ancestorTile) {
13761
- const ancestorMesh = this._ancestorMeshCache.getMesh(targetCoord, ancestorTile.coord, this._config.segmentsPerSide ?? 16);
13762
- ancestorTile.drawRemapped(ancestorMesh, pMatrix, vMatrix, mMatrix);
13763
- }
13764
- }
13765
- tile?.draw(pMatrix, vMatrix, mMatrix, this._tilePriorities.get(tileKey) ?? 0);
13766
- }
13767
- }
13768
- evictCache() {
13769
- const maxCachedTiles = this._config.maxCachedTiles ?? XYZLayer.DEFAULT_MAX_CACHED_TILES;
13770
- this._tileBuffer.evictCached(maxCachedTiles);
13771
- }
13772
- disposeTiles() {
13773
- this._tileBuffer.dispose();
13774
- this._ancestorMeshCache.dispose();
13775
- this._visibleTileKeys = [];
13776
- this._fallbackVisibleTileKeys = [];
13777
- this._baseVisibleTileKeys = [];
13778
- }
13779
- getTileKey(tileCoord) {
13780
- return `${tileCoord.z}/${tileCoord.x}/${tileCoord.y}`;
13781
- }
13782
- parseTileKey(tileKey) {
13783
- const [zRaw, xRaw, yRaw] = tileKey.split('/');
13784
- const z = Number.parseInt(zRaw ?? '', 10);
13785
- const x = Number.parseInt(xRaw ?? '', 10);
13786
- const y = Number.parseInt(yRaw ?? '', 10);
13787
- if (!Number.isFinite(z) || !Number.isFinite(x) || !Number.isFinite(y)) {
13788
- return null;
13789
- }
13790
- return { z, x, y };
13791
- }
13792
- findBestAvailableAncestor(targetCoord) {
13793
- for (let z = targetCoord.z - 1; z >= this._provider.minZoom; z--) {
13794
- const dz = targetCoord.z - z;
13795
- const ancestorCoord = {
13796
- z,
13797
- x: targetCoord.x >> dz,
13798
- y: targetCoord.y >> dz,
13799
- };
13800
- const ancestor = this._tileBuffer.getAnyTile(this.getTileKey(ancestorCoord));
13801
- if (ancestor?.ready) {
13802
- return ancestor;
13803
- }
13804
- }
13805
- return null;
13806
- }
13807
- }
13808
- exports.XYZLayer = XYZLayer;
13809
-
13810
-
13811
14039
  /***/ }),
13812
14040
 
13813
14041
  /***/ 2737:
13814
- /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
14042
+ /***/ ((__unused_webpack_module, exports) => {
13815
14043
 
13816
14044
 
14045
+ /*
14046
+ * AstroViewer
14047
+ * Copyright (C) Fabrizio Giordano
14048
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
14049
+ *
14050
+ * This file is part of AstroViewer.
14051
+ * AstroViewer is distributed under a dual-license model.
14052
+ * Commercial use requires a separate commercial license.
14053
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
14054
+ *
14055
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
14056
+ */
13817
14057
  Object.defineProperty(exports, "__esModule", ({ value: true }));
13818
14058
  exports.XYZTileBuffer = void 0;
13819
- const XYZTile_js_1 = __webpack_require__(1375);
13820
14059
  class XYZTileBuffer {
13821
14060
  _tiles = new Map();
13822
14061
  _cachedTiles = new Map();
13823
14062
  _cacheAliveMilliSeconds;
13824
14063
  _cleanerId;
13825
- _webgl;
13826
- _meshBuilder;
13827
- _shaderProgram;
13828
- constructor(minutesToLiveInCache = 1, webgl, meshBuilder, shaderProgram) {
14064
+ constructor(minutesToLiveInCache = 1) {
13829
14065
  this._cacheAliveMilliSeconds = minutesToLiveInCache * 60 * 1000;
13830
- this._webgl = webgl;
13831
- this._meshBuilder = meshBuilder;
13832
- this._shaderProgram = shaderProgram;
13833
- this._cleanerId = window.setInterval(() => {
13834
- this.cacheCleaner();
13835
- }, 10_000);
14066
+ if (typeof window !== 'undefined') {
14067
+ this._cleanerId = window.setInterval(() => {
14068
+ this.cacheCleaner();
14069
+ }, 10_000);
14070
+ }
13836
14071
  }
13837
14072
  get activeTiles() {
13838
14073
  return this._tiles;
@@ -13843,64 +14078,31 @@ class XYZTileBuffer {
13843
14078
  get size() {
13844
14079
  return this._tiles.size + this._cachedTiles.size;
13845
14080
  }
13846
- getTile(tileCoord, url, segmentsPerSide, role) {
13847
- const tileKey = this.key(tileCoord);
13848
- if (!this._tiles.has(tileKey)) {
13849
- if (this._cachedTiles.has(tileKey)) {
13850
- const entry = this._cachedTiles.get(tileKey);
13851
- entry.cacheTime0 = undefined;
13852
- entry.role = role;
13853
- this._tiles.set(tileKey, entry);
13854
- this._cachedTiles.delete(tileKey);
13855
- }
13856
- else {
13857
- const mesh = this._meshBuilder.buildTileMesh(tileCoord, segmentsPerSide);
13858
- this._tiles.set(tileKey, {
13859
- tile: new XYZTile_js_1.XYZTile(tileCoord, url, mesh, this._webgl, this._shaderProgram),
13860
- role,
13861
- });
13862
- }
13863
- }
13864
- else {
13865
- const entry = this._tiles.get(tileKey);
13866
- entry.role = role;
14081
+ ensureTiles(visibleTiles, tileFactory) {
14082
+ const visibleTileKeys = [];
14083
+ for (const tileCoord of visibleTiles) {
14084
+ const tile = this.getTile(tileCoord, tileFactory);
14085
+ this.touchTile(tile);
14086
+ visibleTileKeys.push(this.key(tileCoord));
13867
14087
  }
13868
- return this._tiles.get(tileKey).tile;
14088
+ this.syncVisibleTiles(visibleTileKeys);
14089
+ return visibleTileKeys;
13869
14090
  }
13870
- getExistingTile(tileCoord, role) {
14091
+ getTile(tileCoord, tileFactory) {
13871
14092
  const tileKey = this.key(tileCoord);
13872
14093
  if (this._tiles.has(tileKey)) {
13873
- const entry = this._tiles.get(tileKey);
13874
- entry.role = role;
13875
- return entry.tile;
14094
+ return this._tiles.get(tileKey).tile;
13876
14095
  }
13877
14096
  if (this._cachedTiles.has(tileKey)) {
13878
14097
  const entry = this._cachedTiles.get(tileKey);
13879
14098
  entry.cacheTime0 = undefined;
13880
- entry.role = role;
13881
14099
  this._tiles.set(tileKey, entry);
13882
14100
  this._cachedTiles.delete(tileKey);
13883
14101
  return entry.tile;
13884
14102
  }
13885
- return null;
13886
- }
13887
- ensureTiles(requests, segmentsPerSide) {
13888
- const visibleTileKeys = [];
13889
- for (const request of requests) {
13890
- const tile = request.role === 'fallback'
13891
- ? this.getExistingTile(request.tileCoord, 'fallback')
13892
- : this.getTile(request.tileCoord, request.url, segmentsPerSide, request.role);
13893
- if (!tile) {
13894
- continue;
13895
- }
13896
- tile.touch();
13897
- if (request.role !== 'fallback') {
13898
- tile.primeLoad(request.priority);
13899
- }
13900
- visibleTileKeys.push(this.key(request.tileCoord));
13901
- }
13902
- this.syncVisibleTiles(visibleTileKeys);
13903
- return visibleTileKeys;
14103
+ const tile = tileFactory(tileCoord);
14104
+ this._tiles.set(tileKey, { tile });
14105
+ return tile;
13904
14106
  }
13905
14107
  getActiveTile(tileKey) {
13906
14108
  return this._tiles.get(tileKey)?.tile ?? null;
@@ -13908,11 +14110,14 @@ class XYZTileBuffer {
13908
14110
  getAnyTile(tileKey) {
13909
14111
  return this._tiles.get(tileKey)?.tile ?? this._cachedTiles.get(tileKey)?.tile ?? null;
13910
14112
  }
14113
+ getActiveTiles() {
14114
+ return Array.from(this._tiles.values(), (entry) => entry.tile);
14115
+ }
13911
14116
  syncVisibleTiles(visibleTileKeys) {
13912
14117
  const visibleKeySet = new Set(visibleTileKeys);
13913
14118
  for (const [tileKey, entry] of this._tiles) {
13914
14119
  if (visibleKeySet.has(tileKey)) {
13915
- entry.tile.touch();
14120
+ this.touchTile(entry.tile);
13916
14121
  continue;
13917
14122
  }
13918
14123
  entry.cacheTime0 = Date.now();
@@ -13925,9 +14130,7 @@ class XYZTileBuffer {
13925
14130
  return;
13926
14131
  }
13927
14132
  const candidates = Array.from(this._cachedTiles.entries()).sort((a, b) => {
13928
- const scoreA = Math.min(a[1].tile.lastUsedAt || a[1].tile.createdAt, a[1].tile.createdAt);
13929
- const scoreB = Math.min(b[1].tile.lastUsedAt || b[1].tile.createdAt, b[1].tile.createdAt);
13930
- return scoreA - scoreB;
14133
+ return this.getTileAgeScore(a[1].tile) - this.getTileAgeScore(b[1].tile);
13931
14134
  });
13932
14135
  for (const [tileKey, entry] of candidates) {
13933
14136
  if (this.size <= maxCachedTiles) {
@@ -13936,33 +14139,48 @@ class XYZTileBuffer {
13936
14139
  if (entry.tile.loading) {
13937
14140
  continue;
13938
14141
  }
13939
- entry.tile.dispose();
14142
+ entry.tile.dispose?.();
13940
14143
  this._cachedTiles.delete(tileKey);
13941
14144
  }
13942
14145
  }
13943
14146
  dispose() {
13944
- window.clearInterval(this._cleanerId);
14147
+ if (this._cleanerId !== undefined && typeof window !== 'undefined') {
14148
+ window.clearInterval(this._cleanerId);
14149
+ this._cleanerId = undefined;
14150
+ }
13945
14151
  for (const entry of this._tiles.values()) {
13946
- entry.tile.dispose();
14152
+ entry.tile.dispose?.();
13947
14153
  }
13948
14154
  for (const entry of this._cachedTiles.values()) {
13949
- entry.tile.dispose();
14155
+ entry.tile.dispose?.();
13950
14156
  }
13951
14157
  this._tiles.clear();
13952
14158
  this._cachedTiles.clear();
13953
14159
  }
14160
+ key(tileCoord) {
14161
+ return XYZTileBuffer.key(tileCoord);
14162
+ }
14163
+ static key(tileCoord) {
14164
+ return `${tileCoord.z}/${tileCoord.x}/${tileCoord.y}`;
14165
+ }
13954
14166
  cacheCleaner() {
13955
14167
  const now = Date.now();
13956
14168
  for (const [tileKey, entry] of this._cachedTiles) {
13957
14169
  const t0 = entry.cacheTime0;
13958
- if (t0 !== undefined && now - t0 > this._cacheAliveMilliSeconds && !entry.tile.loading) {
13959
- entry.tile.dispose();
13960
- this._cachedTiles.delete(tileKey);
14170
+ if (t0 === undefined || now - t0 <= this._cacheAliveMilliSeconds || entry.tile.loading) {
14171
+ continue;
13961
14172
  }
14173
+ entry.tile.dispose?.();
14174
+ this._cachedTiles.delete(tileKey);
13962
14175
  }
13963
14176
  }
13964
- key(tileCoord) {
13965
- return `${tileCoord.z}/${tileCoord.x}/${tileCoord.y}`;
14177
+ touchTile(tile) {
14178
+ tile.touch?.();
14179
+ }
14180
+ getTileAgeScore(tile) {
14181
+ const lastUsedAt = tile.lastUsedAt ?? 0;
14182
+ const createdAt = tile.createdAt ?? lastUsedAt;
14183
+ return Math.min(lastUsedAt || createdAt, createdAt);
13966
14184
  }
13967
14185
  }
13968
14186
  exports.XYZTileBuffer = XYZTileBuffer;
@@ -13973,6 +14191,18 @@ exports.XYZTileBuffer = XYZTileBuffer;
13973
14191
  /***/ 2885:
13974
14192
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
13975
14193
 
14194
+ /*
14195
+ * AstroViewer
14196
+ * Copyright (C) Fabrizio Giordano
14197
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
14198
+ *
14199
+ * This file is part of AstroViewer.
14200
+ * AstroViewer is distributed under a dual-license model.
14201
+ * Commercial use requires a separate commercial license.
14202
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
14203
+ *
14204
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
14205
+ */
13976
14206
 
13977
14207
  var __importDefault = (this && this.__importDefault) || function (mod) {
13978
14208
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -14232,6 +14462,18 @@ exports["default"] = AncestorTile;
14232
14462
  /***/ ((__unused_webpack_module, exports) => {
14233
14463
 
14234
14464
 
14465
+ /*
14466
+ * AstroViewer
14467
+ * Copyright (C) Fabrizio Giordano
14468
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
14469
+ *
14470
+ * This file is part of AstroViewer.
14471
+ * AstroViewer is distributed under a dual-license model.
14472
+ * Commercial use requires a separate commercial license.
14473
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
14474
+ *
14475
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
14476
+ */
14235
14477
  Object.defineProperty(exports, "__esModule", ({ value: true }));
14236
14478
  exports.bootSetup = exports.tapRepos = exports.hipsNodes = void 0;
14237
14479
  exports.hipsNodes = [
@@ -14273,6 +14515,18 @@ exports.bootSetup = {
14273
14515
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
14274
14516
 
14275
14517
 
14518
+ /*
14519
+ * AstroViewer
14520
+ * Copyright (C) Fabrizio Giordano
14521
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
14522
+ *
14523
+ * This file is part of AstroViewer.
14524
+ * AstroViewer is distributed under a dual-license model.
14525
+ * Commercial use requires a separate commercial license.
14526
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
14527
+ *
14528
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
14529
+ */
14276
14530
  var __importDefault = (this && this.__importDefault) || function (mod) {
14277
14531
  return (mod && mod.__esModule) ? mod : { "default": mod };
14278
14532
  };
@@ -14545,12 +14799,122 @@ class GeomUtils {
14545
14799
  exports["default"] = GeomUtils;
14546
14800
 
14547
14801
 
14802
+ /***/ }),
14803
+
14804
+ /***/ 3174:
14805
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
14806
+
14807
+
14808
+ /*
14809
+ * AstroViewer
14810
+ * Copyright (C) Fabrizio Giordano
14811
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
14812
+ *
14813
+ * This file is part of AstroViewer.
14814
+ * AstroViewer is distributed under a dual-license model.
14815
+ * Commercial use requires a separate commercial license.
14816
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
14817
+ *
14818
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
14819
+ */
14820
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
14821
+ exports.XYZAncestorTile = exports.XYZAnchestorTile = void 0;
14822
+ const XYZMeshBuilder_js_1 = __webpack_require__(8819);
14823
+ const XYZTile_js_1 = __webpack_require__(1375);
14824
+ class XYZAnchestorTile extends XYZTile_js_1.XYZTile {
14825
+ _ancestorMeshBuilder;
14826
+ _ancestorWebgl;
14827
+ _segmentsPerSide;
14828
+ _meshCache = new Map();
14829
+ constructor(coord, url, webgl, shaderProgram, meshBuilder = new XYZMeshBuilder_js_1.XYZMeshBuilder(), segmentsPerSide = 16) {
14830
+ super(coord, url, webgl, shaderProgram, meshBuilder, segmentsPerSide);
14831
+ this._ancestorMeshBuilder = meshBuilder;
14832
+ this._ancestorWebgl = webgl;
14833
+ this._segmentsPerSide = segmentsPerSide;
14834
+ }
14835
+ draw(pMatrixOrVisibleZoom, vMatrixOrVisibleTiles, mMatrixOrAncestorsMap, colorMapIdxOrPMatrix, vMatrix, mMatrix, colorMapIdx) {
14836
+ if (typeof pMatrixOrVisibleZoom !== 'number') {
14837
+ return super.draw(pMatrixOrVisibleZoom, vMatrixOrVisibleTiles, mMatrixOrAncestorsMap, colorMapIdxOrPMatrix);
14838
+ }
14839
+ if (!vMatrix || !mMatrix || colorMapIdx === undefined) {
14840
+ return false;
14841
+ }
14842
+ const visibleZoom = pMatrixOrVisibleZoom;
14843
+ const visibleTiles = vMatrixOrVisibleTiles;
14844
+ const ancestorsMap = mMatrixOrAncestorsMap;
14845
+ const pMatrix = colorMapIdxOrPMatrix;
14846
+ let drawn = false;
14847
+ if (visibleZoom <= this.coord.z) {
14848
+ return super.draw(pMatrix, vMatrix, mMatrix, colorMapIdx);
14849
+ }
14850
+ for (const targetTile of visibleTiles) {
14851
+ if (!this.isAncestorOf(targetTile)) {
14852
+ continue;
14853
+ }
14854
+ const ancestorKey = `${this.coord.z}/${this.coord.x}/${this.coord.y}`;
14855
+ if (!ancestorsMap.has(ancestorKey)) {
14856
+ continue;
14857
+ }
14858
+ const mesh = this.getRemappedMesh(targetTile);
14859
+ drawn = super.drawRemapped(mesh, pMatrix, vMatrix, mMatrix, colorMapIdx) || drawn;
14860
+ }
14861
+ return drawn;
14862
+ }
14863
+ dispose() {
14864
+ for (const mesh of this._meshCache.values()) {
14865
+ if (mesh.positionBuffer)
14866
+ this._ancestorWebgl.deleteBuffer(mesh.positionBuffer);
14867
+ if (mesh.uvBuffer)
14868
+ this._ancestorWebgl.deleteBuffer(mesh.uvBuffer);
14869
+ if (mesh.indexBuffer)
14870
+ this._ancestorWebgl.deleteBuffer(mesh.indexBuffer);
14871
+ }
14872
+ this._meshCache.clear();
14873
+ super.dispose();
14874
+ }
14875
+ getRemappedMesh(targetTile) {
14876
+ const key = `${targetTile.z}/${targetTile.x}/${targetTile.y}->${this.coord.z}/${this.coord.x}/${this.coord.y}`;
14877
+ const existing = this._meshCache.get(key);
14878
+ if (existing) {
14879
+ return existing;
14880
+ }
14881
+ const mesh = this._ancestorMeshBuilder.buildAncestorMesh(targetTile, this.coord, this._segmentsPerSide);
14882
+ const uploaded = this._ancestorMeshBuilder.uploadMesh(mesh, this._ancestorWebgl);
14883
+ this._meshCache.set(key, uploaded);
14884
+ return uploaded;
14885
+ }
14886
+ isAncestorOf(targetTile) {
14887
+ if (targetTile.z <= this.coord.z) {
14888
+ return targetTile.z === this.coord.z
14889
+ && targetTile.x === this.coord.x
14890
+ && targetTile.y === this.coord.y;
14891
+ }
14892
+ const dz = targetTile.z - this.coord.z;
14893
+ return (targetTile.x >> dz) === this.coord.x && (targetTile.y >> dz) === this.coord.y;
14894
+ }
14895
+ }
14896
+ exports.XYZAnchestorTile = XYZAnchestorTile;
14897
+ exports.XYZAncestorTile = XYZAnchestorTile;
14898
+
14899
+
14548
14900
  /***/ }),
14549
14901
 
14550
14902
  /***/ 3559:
14551
14903
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
14552
14904
 
14553
14905
 
14906
+ /*
14907
+ * AstroViewer
14908
+ * Copyright (C) Fabrizio Giordano
14909
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
14910
+ *
14911
+ * This file is part of AstroViewer.
14912
+ * AstroViewer is distributed under a dual-license model.
14913
+ * Commercial use requires a separate commercial license.
14914
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
14915
+ *
14916
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
14917
+ */
14554
14918
  var __importDefault = (this && this.__importDefault) || function (mod) {
14555
14919
  return (mod && mod.__esModule) ? mod : { "default": mod };
14556
14920
  };
@@ -14654,310 +15018,33 @@ exports.CatalogueShaderProgram = CatalogueShaderProgram;
14654
15018
 
14655
15019
  /***/ }),
14656
15020
 
14657
- /***/ 3576:
15021
+ /***/ 3726:
14658
15022
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
14659
15023
 
15024
+ /*
15025
+ * AstroViewer
15026
+ * Copyright (C) Fabrizio Giordano
15027
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
15028
+ *
15029
+ * This file is part of AstroViewer.
15030
+ * AstroViewer is distributed under a dual-license model.
15031
+ * Commercial use requires a separate commercial license.
15032
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
15033
+ *
15034
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
15035
+ */
14660
15036
 
14661
15037
  var __importDefault = (this && this.__importDefault) || function (mod) {
14662
15038
  return (mod && mod.__esModule) ? mod : { "default": mod };
14663
15039
  };
14664
15040
  Object.defineProperty(exports, "__esModule", ({ value: true }));
14665
- exports.FoV = void 0;
15041
+ exports.HiPS = void 0;
14666
15042
  /**
14667
- * FoV singleton (TypeScript)
14668
- * - Uses computePerspectiveMatrixSingleton.pMatrix
14669
- * - Guards acos domain (numeric safety)
14670
- * - Uses vec3.transformMat4 instead of custom mat4*vec3
14671
- * - Keeps original “insideSphere ? 360 - angle : angle” behavior
14672
- */
14673
- const gl_matrix_1 = __webpack_require__(1961);
14674
- const RayPickingUtils_js_1 = __importDefault(__webpack_require__(4639));
14675
- const Utils_js_1 = __webpack_require__(7930);
14676
- class FoV {
14677
- static MIN_FOV_DEG = 1e-6;
14678
- fovXDeg = 180;
14679
- fovYDeg = 180;
14680
- ratio = +0;
14681
- _minFoV = 180;
14682
- _webgl;
14683
- constructor(webgl) {
14684
- this._webgl = webgl;
14685
- }
14686
- /** Recomputes FoV for current camera + projection */
14687
- getFoV(insideSphere, healpixGridSingleton, camera, pMatrix) {
14688
- // const gl = webgl
14689
- const gl = this._webgl;
14690
- if (!gl || !gl.canvas) {
14691
- // Handle the error or assign default values
14692
- this.fovXDeg = 180;
14693
- this.fovYDeg = 180;
14694
- this._minFoV = this.minFoV;
14695
- return this;
14696
- }
14697
- // horizontal FoV: ray through (centerY)
14698
- // const xFoVComputed = this.computeAngle(0, gl.canvas.height / 2, insideSphere, healpixGridSingleton, camera)
14699
- const canvas = gl.canvas;
14700
- const rect = canvas.getBoundingClientRect();
14701
- const canvasWidth = rect.width;
14702
- const canvasHeight = rect.height;
14703
- // const xFoVComputed = this.computeAngle(0, gl.canvas.height / 2, insideSphere, healpixGridSingleton, camera, pMatrix)
14704
- const xFoVComputed = this.computeAngle(0, canvasHeight / 2, insideSphere, healpixGridSingleton, camera, pMatrix);
14705
- this.fovXDeg = xFoVComputed.angleDeg;
14706
- // vertical FoV: ray through (centerX)
14707
- // const yFoVComputed = this.computeAngle(gl.canvas.width / 2, 0, insideSphere, healpixGridSingleton, camera, pMatrix)
14708
- const yFoVComputed = this.computeAngle(canvasWidth / 2, 0, insideSphere, healpixGridSingleton, camera, pMatrix);
14709
- this.fovYDeg = yFoVComputed.angleDeg;
14710
- this._minFoV = this.minFoV;
14711
- this.ratio = this.computeRatio(camera);
14712
- return this;
14713
- }
14714
- computeRatio(camera) {
14715
- // const camera = global.camera
14716
- if (!camera)
14717
- throw Error("Camera not defined");
14718
- const pos = camera.getCameraPosition();
14719
- const distanceFromCenter = Math.sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]);
14720
- // const distanceFromSphere = distanceFromCenter - healpixGridSingleton.RADIUS
14721
- const ratio = distanceFromCenter / this.fovYDeg;
14722
- return ratio;
14723
- }
14724
- changeMinFov(deg) {
14725
- console.log("inside changeMinFov");
14726
- if (this.fovYDeg <= this.fovXDeg) {
14727
- this.fovYDeg = deg;
14728
- }
14729
- else {
14730
- this.fovXDeg = deg;
14731
- }
14732
- console.log("changeMinFov: ping");
14733
- this.minFoV;
14734
- // this.fovYDeg <= this.fovXDeg ? this.fovYDeg = deg : this.fovXDeg = deg
14735
- }
14736
- get minFoV() {
14737
- const minFov = this.fovYDeg <= this.fovXDeg ? this.fovYDeg : this.fovXDeg;
14738
- this._minFoV = Math.max(minFov, FoV.MIN_FOV_DEG);
14739
- return this._minFoV;
14740
- }
14741
- get xFoV() {
14742
- return this.fovXDeg;
14743
- }
14744
- get yFoV() {
14745
- return this.fovYDeg;
14746
- }
14747
- computeDistanceFromAngle(angleDeg) {
14748
- const desiredFoV = angleDeg;
14749
- const distance = desiredFoV * this.ratio;
14750
- // return Math.abs(distance)
14751
- return distance;
14752
- }
14753
- /** FoV half-screen chord angle doubled (deg) along a given canvas axis */
14754
- computeAngle(canvasX, canvasY, insideSphere, healpixGridSingleton, camera, pMatrix) {
14755
- // const pMatrix = computePerspectiveMatrixSingleton.pMatrix
14756
- if (!pMatrix) {
14757
- // Handle the error or assign a default value
14758
- console.warn('FoV: projection matrix is null');
14759
- return { angleDeg: 180, distance: 1 };
14760
- }
14761
- const vMatrix = camera.getCameraMatrix();
14762
- if (!camera) {
14763
- // Handle the error or assign a default value
14764
- console.warn('FoV: camera is null');
14765
- return { angleDeg: 180, distance: 1 };
14766
- }
14767
- const rayWorld = RayPickingUtils_js_1.default.getRayFromMouse(canvasX, canvasY, pMatrix, this._webgl, vMatrix);
14768
- const intersectionDistance = RayPickingUtils_js_1.default.raySphere(camera.getCameraPosition(), rayWorld, healpixGridSingleton);
14769
- let angleDeg;
14770
- if (intersectionDistance > 0) {
14771
- // world-space intersection point on the sphere
14772
- const hit = gl_matrix_1.vec3.create();
14773
- gl_matrix_1.vec3.scale(hit, rayWorld, intersectionDistance);
14774
- gl_matrix_1.vec3.add(hit, camera.getCameraPosition(), hit);
14775
- const center = healpixGridSingleton.center;
14776
- // vectors from sphere center
14777
- const vHit = gl_matrix_1.vec3.create();
14778
- gl_matrix_1.vec3.subtract(vHit, hit, center);
14779
- // reference vector: rotate world +Z into current camera orientation, then from center
14780
- const refWorldZ = gl_matrix_1.vec3.fromValues(center[0], center[1], center[2] + healpixGridSingleton.radius);
14781
- const vInv = gl_matrix_1.mat4.create();
14782
- gl_matrix_1.mat4.invert(vInv, camera.getCameraMatrix());
14783
- const refCamZ = gl_matrix_1.vec3.create();
14784
- gl_matrix_1.vec3.transformMat4(refCamZ, refWorldZ, vInv);
14785
- const vRef = gl_matrix_1.vec3.create();
14786
- gl_matrix_1.vec3.subtract(vRef, refCamZ, center);
14787
- // angle between vHit and vRef, doubled
14788
- const dot = gl_matrix_1.vec3.dot(vHit, vRef);
14789
- const n1 = gl_matrix_1.vec3.length(vHit);
14790
- const n2 = gl_matrix_1.vec3.length(vRef);
14791
- // numeric safety for acos
14792
- const c = Math.min(1, Math.max(-1, dot / (n1 * n2)));
14793
- const angleRad = Math.acos(c);
14794
- angleDeg = 2 * (0, Utils_js_1.radToDeg)(angleRad);
14795
- }
14796
- else {
14797
- angleDeg = 180;
14798
- }
14799
- const finalAngle = insideSphere ? 360 - angleDeg : angleDeg;
14800
- // return insideSphere ? 360 - angleDeg : angleDeg
14801
- return { angleDeg: finalAngle, distance: intersectionDistance };
14802
- }
14803
- /**
14804
- * Computes the camera position (x,y,z) along the current view direction that would
14805
- * yield the requested minFoV (in degrees), assuming the camera is OUTSIDE the sphere.
14806
- * This method does NOT mutate the camera; it only returns the suggested position.
14807
- *
14808
- * Geometry: for a sphere of radius R observed from distance d (from center),
14809
- * the apparent angular diameter is 2*arcsin(R/d). Our minFoV is that angular diameter
14810
- * along the tighter axis; we solve for d and place the camera on the current
14811
- * center→camera direction with that distance.
14812
- *
14813
- * @param targetMinFoVDeg Desired min FoV in degrees, 0 < targetMinFoVDeg < 180
14814
- * @returns Tuple [x, y, z] for the recommended camera position in world coordinates.
14815
- */
14816
- computeCameraPositionForMinFoV(targetMinFoVDeg) {
14817
- // const camera = global.camera
14818
- // const center = healpixGridSingleton.center
14819
- // const R = healpixGridSingleton.radius
14820
- // if (!camera) {
14821
- // console.warn('FoV.computeCameraPositionForMinFoV: camera not available; returning a sensible default.')
14822
- // return [center[0], center[1], center[2] + 2 * R]
14823
- // }
14824
- // // Clamp and validate input
14825
- // const eps = 1e-6
14826
- // const clamped = Math.max(eps, Math.min(180 - eps, targetMinFoVDeg))
14827
- // const halfRad = (clamped * Math.PI / 180) * 0.5
14828
- // // Distance from center needed to achieve the angular diameter
14829
- // // minFoV = 2 * arcsin(R / d) => d = R / sin(minFoV/2)
14830
- // const sinHalf = Math.sin(halfRad)
14831
- // if (sinHalf <= 0) {
14832
- // console.warn('FoV.computeCameraPositionForMinFoV: invalid targetMinFoVDeg, using fallback.')
14833
- // return [center[0], center[1], center[2] + 2 * R]
14834
- // }
14835
- // let d = R / sinHalf
14836
- // // Ensure we remain strictly outside the sphere
14837
- // d = Math.max(d, R + 1e-4)
14838
- // // Use the current center→camera direction to keep orientation
14839
- // const camPos = camera.getCameraPosition()
14840
- // let dirX = camPos[0] - center[0]
14841
- // let dirY = camPos[1] - center[1]
14842
- // let dirZ = camPos[2] - center[2]
14843
- // const len = Math.hypot(dirX, dirY, dirZ)
14844
- // if (len < eps) {
14845
- // // If somehow at the center, use +Z as a default direction
14846
- // dirX = 0; dirY = 0; dirZ = 1;
14847
- // } else {
14848
- // dirX /= len
14849
- // dirY /= len
14850
- // dirZ /= len
14851
- // }
14852
- // const newX = center[0] + dirX * d
14853
- // const newY = center[1] + dirY * d
14854
- // const newZ = center[2] + dirZ * d
14855
- // return [newX, newY, newZ]
14856
- return [0, 0, 0];
14857
- }
14858
- /**
14859
- * Computes the camera world-space position required to achieve a target FoV (deg),
14860
- * keeping the same viewing direction. Acts as the inverse of computeAngle().
14861
- *
14862
- * @param targetFoVDeg desired full FoV angle in degrees (0 < FoV < 180)
14863
- * @param canvasWidth canvas width in pixels
14864
- * @param canvasHeight canvas height in pixels
14865
- * @returns [x, y, z] coordinates for the new camera position
14866
- */
14867
- computeCameraPositionForFoV(targetFoVDeg) {
14868
- // const camera = global.camera;
14869
- // const center = healpixGridSingleton.center;
14870
- // const R = healpixGridSingleton.radius;
14871
- // if (!camera) {
14872
- // console.warn("FoV.computeCameraPositionForFoV: camera missing.");
14873
- // return [center[0], center[1], center[2] + 2 * R];
14874
- // }
14875
- // const eps = 1e-6;
14876
- // const clamped = Math.max(eps, Math.min(180 - eps, targetFoVDeg));
14877
- // const halfRad = (clamped * Math.PI) / 360.0; // half-angle in radians
14878
- // // Distance from center that yields this FoV
14879
- // const sinHalf = Math.sin(halfRad);
14880
- // if (sinHalf <= 0) {
14881
- // console.warn("FoV.computeCameraPositionForFoV: invalid FoV.");
14882
- // return [center[0], center[1], center[2] + 2 * R];
14883
- // }
14884
- // let d = R / sinHalf;
14885
- // // Slightly outside sphere to avoid clipping
14886
- // d = Math.max(d, R + 1e-4);
14887
- // // Get current viewing direction
14888
- // const camPos = camera.getCameraPosition();
14889
- // let dirX = camPos[0] - center[0];
14890
- // let dirY = camPos[1] - center[1];
14891
- // let dirZ = camPos[2] - center[2];
14892
- // const len = Math.hypot(dirX, dirY, dirZ);
14893
- // if (len < eps) {
14894
- // dirX = 0; dirY = 0; dirZ = 1;
14895
- // } else {
14896
- // dirX /= len;
14897
- // dirY /= len;
14898
- // dirZ /= len;
14899
- // }
14900
- // const newX = center[0] + dirX * d;
14901
- // const newY = center[1] + dirY * d;
14902
- // const newZ = center[2] + dirZ * d;
14903
- // return [newX, newY, newZ];
14904
- return [0, 0, 0];
14905
- }
14906
- /**
14907
- * Return a camera position such that the sphere's apparent angular diameter
14908
- * (the silhouette, not the surface coverage) equals targetAngularDiameterDeg.
14909
- * Keeps current view direction; does not mutate the camera.
14910
- *
14911
- * @param targetAngularDiameterDeg desired apparent diameter in degrees (0<α<180)
14912
- * @returns [x,y,z] world position
14913
- */
14914
- computeCameraPositionForAngularDiameter(targetAngularDiameterDeg) {
14915
- // const camera = global.camera;
14916
- // const center = healpixGridSingleton.center;
14917
- // const R = healpixGridSingleton.radius;
14918
- // if (!camera) {
14919
- // console.warn('computeCameraPositionForAngularDiameter: camera missing.');
14920
- // return [center[0], center[1], center[2] + 2 * R];
14921
- // }
14922
- // const eps = 1e-6;
14923
- // const α = Math.max(eps, Math.min(180 - eps, targetAngularDiameterDeg));
14924
- // const half = (α * Math.PI) / 360.0;
14925
- // const sinHalf = Math.sin(half);
14926
- // // d = R / sin(α/2)
14927
- // let d = R / sinHalf;
14928
- // d = Math.max(d, R + 1e-4); // stay outside
14929
- // // project along current center→camera direction
14930
- // const [cx, cy, cz] = center as [number, number, number];
14931
- // const [px, py, pz] = camera.getCameraPosition();
14932
- // let dx = px - cx, dy = py - cy, dz = pz - cz;
14933
- // const L = Math.hypot(dx, dy, dz);
14934
- // if (L < eps) { dx = 0; dy = 0; dz = 1; } else { dx /= L; dy /= L; dz /= L; }
14935
- // return [cx + dx * d, cy + dy * d, cz + dz * d];
14936
- return [0, 0, 0];
14937
- }
14938
- }
14939
- exports.FoV = FoV;
14940
-
14941
-
14942
- /***/ }),
14943
-
14944
- /***/ 3726:
14945
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
14946
-
14947
-
14948
- var __importDefault = (this && this.__importDefault) || function (mod) {
14949
- return (mod && mod.__esModule) ? mod : { "default": mod };
14950
- };
14951
- Object.defineProperty(exports, "__esModule", ({ value: true }));
14952
- exports.HiPS = void 0;
14953
- /**
14954
- * @author Fabrizio Giordano (Fab77)
15043
+ * @author Fabrizio Giordano (Fab77)
14955
15044
  */
14956
15045
  const AbstractSkyEntity_js_1 = __webpack_require__(4735);
14957
15046
  const FoVHelper_js_1 = __webpack_require__(229);
14958
15047
  const ColorMaps_js_1 = __importDefault(__webpack_require__(619));
14959
- // import { hipsShaderProgram } from '../../shader/HiPSShaderProgram.js'
14960
- // import { HiPSShaderProgram } from '../../shader/HiPSShaderProgram.js'
14961
15048
  const AncestorTile_js_1 = __importDefault(__webpack_require__(2885));
14962
15049
  const AllSky_js_1 = __importDefault(__webpack_require__(2368));
14963
15050
  class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
@@ -14984,10 +15071,8 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14984
15071
  constructor(radius, position, xrad, yrad, descriptor, webgl, healpixGrid) {
14985
15072
  super(radius, position, xrad, yrad, descriptor.surveyName, webgl, descriptor.isGalactic);
14986
15073
  this._descriptor = descriptor;
14987
- // this.initGL((global as any).gl as WebGL2RenderingContext)
14988
15074
  this.initGL(webgl);
14989
15075
  this._healpixGrid = healpixGrid;
14990
- // newTileBuffer.addHiPS(this)
14991
15076
  this._healpixGrid.visibleTilesManager.tileBuffer.addHiPS(this);
14992
15077
  // DEBUG logs kept from JS (optional)
14993
15078
  // eslint-disable-next-line no-console
@@ -15136,7 +15221,6 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15136
15221
  if (!pMatrix)
15137
15222
  return;
15138
15223
  this.refresh();
15139
- // const pMatrix = computePerspectiveMatrixSingleton.pMatrix as Float32Array
15140
15224
  const mMatrix = this.getModelMatrix();
15141
15225
  super.hipsShaderProgram.setRuntimeColorMap(this.colorMap);
15142
15226
  if (this._allSky && this._allSkyTile) {
@@ -15158,13 +15242,9 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15158
15242
  const order = this.isGalacticHips
15159
15243
  ? this._healpixGrid.visibleTilesManager.galVisibleTilesByOrder.order
15160
15244
  : this._healpixGrid.visibleTilesManager.visibleTilesByOrder.order;
15161
- // ? visibleTilesManager.galVisibleTilesByOrder.order
15162
- // : visibleTilesManager.visibleTilesByOrder.order
15163
15245
  const map = this.isGalacticHips
15164
15246
  ? this._healpixGrid.visibleTilesManager.galAncestorsMap
15165
15247
  : this._healpixGrid.visibleTilesManager.ancestorsMap;
15166
- // ? visibleTilesManager.galAncestorsMap
15167
- // : visibleTilesManager.ancestorsMap
15168
15248
  this._ancestorTiles.forEach((ancestor) => {
15169
15249
  ancestor.draw(order, map, pMatrix, vMatrix, mMatrix, this.colorMapIdx);
15170
15250
  });
@@ -15175,10 +15255,22 @@ exports.HiPS = HiPS;
15175
15255
 
15176
15256
  /***/ }),
15177
15257
 
15178
- /***/ 3768:
15258
+ /***/ 3956:
15179
15259
  /***/ ((__unused_webpack_module, exports) => {
15180
15260
 
15181
15261
 
15262
+ /*
15263
+ * AstroViewer
15264
+ * Copyright (C) Fabrizio Giordano
15265
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
15266
+ *
15267
+ * This file is part of AstroViewer.
15268
+ * AstroViewer is distributed under a dual-license model.
15269
+ * Commercial use requires a separate commercial license.
15270
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
15271
+ *
15272
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
15273
+ */
15182
15274
  Object.defineProperty(exports, "__esModule", ({ value: true }));
15183
15275
  exports.WMTSAdapter = void 0;
15184
15276
  function replaceTokens(template, values) {
@@ -15275,6 +15367,18 @@ exports.WMTSAdapter = WMTSAdapter;
15275
15367
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
15276
15368
 
15277
15369
 
15370
+ /*
15371
+ * AstroViewer
15372
+ * Copyright (C) Fabrizio Giordano
15373
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
15374
+ *
15375
+ * This file is part of AstroViewer.
15376
+ * AstroViewer is distributed under a dual-license model.
15377
+ * Commercial use requires a separate commercial license.
15378
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
15379
+ *
15380
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
15381
+ */
15278
15382
  var __importDefault = (this && this.__importDefault) || function (mod) {
15279
15383
  return (mod && mod.__esModule) ? mod : { "default": mod };
15280
15384
  };
@@ -15435,6 +15539,18 @@ exports.TileBuffer = TileBuffer;
15435
15539
  /***/ 4382:
15436
15540
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
15437
15541
 
15542
+ /*
15543
+ * AstroViewer
15544
+ * Copyright (C) Fabrizio Giordano
15545
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
15546
+ *
15547
+ * This file is part of AstroViewer.
15548
+ * AstroViewer is distributed under a dual-license model.
15549
+ * Commercial use requires a separate commercial license.
15550
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
15551
+ *
15552
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
15553
+ */
15438
15554
 
15439
15555
  Object.defineProperty(exports, "__esModule", ({ value: true }));
15440
15556
  const healpixjs_1 = __webpack_require__(1138);
@@ -15495,6 +15611,18 @@ exports["default"] = global;
15495
15611
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
15496
15612
 
15497
15613
 
15614
+ /*
15615
+ * AstroViewer
15616
+ * Copyright (C) Fabrizio Giordano
15617
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
15618
+ *
15619
+ * This file is part of AstroViewer.
15620
+ * AstroViewer is distributed under a dual-license model.
15621
+ * Commercial use requires a separate commercial license.
15622
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
15623
+ *
15624
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
15625
+ */
15498
15626
  var __importDefault = (this && this.__importDefault) || function (mod) {
15499
15627
  return (mod && mod.__esModule) ? mod : { "default": mod };
15500
15628
  };
@@ -15599,6 +15727,18 @@ exports["default"] = MouseHelper;
15599
15727
  /***/ 4595:
15600
15728
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
15601
15729
 
15730
+ /*
15731
+ * AstroViewer
15732
+ * Copyright (C) Fabrizio Giordano
15733
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
15734
+ *
15735
+ * This file is part of AstroViewer.
15736
+ * AstroViewer is distributed under a dual-license model.
15737
+ * Commercial use requires a separate commercial license.
15738
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
15739
+ *
15740
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
15741
+ */
15602
15742
 
15603
15743
  var __importDefault = (this && this.__importDefault) || function (mod) {
15604
15744
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -15610,7 +15750,7 @@ const Global_js_1 = __importDefault(__webpack_require__(4382));
15610
15750
  const gl_matrix_1 = __webpack_require__(1961);
15611
15751
  const FoVHelper_js_1 = __webpack_require__(229);
15612
15752
  const FoVUtils_js_1 = __webpack_require__(8083);
15613
- const FoV_js_1 = __webpack_require__(3576);
15753
+ const SphereFoV_js_1 = __webpack_require__(5803);
15614
15754
  const CoordsType_js_1 = __webpack_require__(8145);
15615
15755
  const Point_js_1 = __webpack_require__(6553);
15616
15756
  const GridShaderManager_js_1 = __importDefault(__webpack_require__(4707));
@@ -15628,7 +15768,7 @@ class HealpixGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15628
15768
  fragmentShader;
15629
15769
  vertexShader;
15630
15770
  defaultColor = '#ec0acaff';
15631
- gridText = new GridTextHelper_js_1.default();
15771
+ gridText = new GridTextHelper_js_1.default('healpix');
15632
15772
  // private _hipsShaderProgram: HiPSShaderProgram
15633
15773
  _attribLocations = {
15634
15774
  position: 0,
@@ -15665,7 +15805,7 @@ class HealpixGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15665
15805
  this._vertexCataloguePositionBuffer = super.webgl.createBuffer();
15666
15806
  this._indexBuffer = super.webgl.createBuffer();
15667
15807
  this._vertexCataloguePosition = new Float32Array(0);
15668
- this._fovObj = new FoV_js_1.FoV(super.webgl);
15808
+ this._fovObj = new SphereFoV_js_1.SphereFoV(super.webgl);
15669
15809
  }
15670
15810
  get fovObj() {
15671
15811
  return this._fovObj;
@@ -15894,9 +16034,10 @@ class HealpixGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15894
16034
  // NDC divide
15895
16035
  clipspace[0] /= clipspace[3];
15896
16036
  clipspace[1] /= clipspace[3];
15897
- // clip pixels
15898
- const pixelX = (clipspace[0] * 0.5 + 0.5) * gl.canvas.width;
15899
- const pixelY = (clipspace[1] * -0.5 + 0.5) * gl.canvas.height;
16037
+ // clip -> CSS pixels
16038
+ const canvasRect = gl.canvas.getBoundingClientRect();
16039
+ const pixelX = canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width;
16040
+ const pixelY = canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height;
15900
16041
  this.gridText.addHPXDivSet(this._visibleorder + '/' + pixels[p], pixelX, pixelY);
15901
16042
  // gridTextHelper.addHPXDivSet(this._visibleorder + '/' + pixels[p], pixelX, pixelY);
15902
16043
  }
@@ -15917,6 +16058,18 @@ exports.HealpixGrid = HealpixGrid;
15917
16058
  /***/ 4639:
15918
16059
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
15919
16060
 
16061
+ /*
16062
+ * AstroViewer
16063
+ * Copyright (C) Fabrizio Giordano
16064
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
16065
+ *
16066
+ * This file is part of AstroViewer.
16067
+ * AstroViewer is distributed under a dual-license model.
16068
+ * Commercial use requires a separate commercial license.
16069
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
16070
+ *
16071
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
16072
+ */
15920
16073
  /**
15921
16074
  * @author Fabrizio Giordano (Fab)
15922
16075
  */
@@ -16036,6 +16189,18 @@ exports["default"] = RayPickingUtils;
16036
16189
  /***/ 4707:
16037
16190
  /***/ ((__unused_webpack_module, exports) => {
16038
16191
 
16192
+ /*
16193
+ * AstroViewer
16194
+ * Copyright (C) Fabrizio Giordano
16195
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
16196
+ *
16197
+ * This file is part of AstroViewer.
16198
+ * AstroViewer is distributed under a dual-license model.
16199
+ * Commercial use requires a separate commercial license.
16200
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
16201
+ *
16202
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
16203
+ */
16039
16204
  // GridShaderManager.ts
16040
16205
 
16041
16206
  Object.defineProperty(exports, "__esModule", ({ value: true }));
@@ -16073,6 +16238,18 @@ exports["default"] = GridShaderManager;
16073
16238
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
16074
16239
 
16075
16240
 
16241
+ /*
16242
+ * AstroViewer
16243
+ * Copyright (C) Fabrizio Giordano
16244
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
16245
+ *
16246
+ * This file is part of AstroViewer.
16247
+ * AstroViewer is distributed under a dual-license model.
16248
+ * Commercial use requires a separate commercial license.
16249
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
16250
+ *
16251
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
16252
+ */
16076
16253
  var __importDefault = (this && this.__importDefault) || function (mod) {
16077
16254
  return (mod && mod.__esModule) ? mod : { "default": mod };
16078
16255
  };
@@ -16091,9 +16268,11 @@ const EquatorialGrid_js_1 = __webpack_require__(9839);
16091
16268
  const HealpixGrid_js_1 = __webpack_require__(4595);
16092
16269
  const CoordsType_js_1 = __webpack_require__(8145);
16093
16270
  const ColorMaps_js_1 = __importDefault(__webpack_require__(619));
16094
- const XYZLayer_js_1 = __webpack_require__(2502);
16095
16271
  const XYZTileRequestScheduler_js_1 = __webpack_require__(5409);
16096
- const WMTSAdapter_js_1 = __webpack_require__(3768);
16272
+ const WMTSAdapter_js_1 = __webpack_require__(3956);
16273
+ const XYZMapDescriptor_js_1 = __webpack_require__(8868);
16274
+ const XYZMap_js_1 = __webpack_require__(1741);
16275
+ const gl_matrix_1 = __webpack_require__(1961);
16097
16276
  /**
16098
16277
  * AstroSphere — main WebGL scene controller (TS port)
16099
16278
  */
@@ -16118,7 +16297,7 @@ class AstroSphere {
16118
16297
  pointerDownY = null;
16119
16298
  pointerDownAt = 0;
16120
16299
  _activeHiPS = null;
16121
- _activeXYZ = null;
16300
+ _activeXYZ2 = null;
16122
16301
  _activeBaseLayer = null;
16123
16302
  startup = true;
16124
16303
  fov;
@@ -16130,6 +16309,9 @@ class AstroSphere {
16130
16309
  lastHoveredSource = null;
16131
16310
  lastHoveredCatalogue = null;
16132
16311
  zoomSensitivity = 1.0;
16312
+ lockedEastWestRaDeg = null;
16313
+ lockedNorthSouthDecDeg = null;
16314
+ keepCameraNorthUp = false;
16133
16315
  constructor(canvas, webgl) {
16134
16316
  console.log('[AstroSphere] new instance for canvas', canvas.id);
16135
16317
  // Keep global GL context (as in original JS)
@@ -16229,6 +16411,118 @@ class AstroSphere {
16229
16411
  getZoomSensitivity() {
16230
16412
  return this.zoomSensitivity;
16231
16413
  }
16414
+ filterRotationDeltaByAstroLocks(deltaX, deltaY) {
16415
+ const lockEastWest = this._camera.isRotationLockedY();
16416
+ const lockNorthSouth = this._camera.isRotationLockedX();
16417
+ if (!lockEastWest && !lockNorthSouth) {
16418
+ return { deltaX, deltaY };
16419
+ }
16420
+ const center = RayPickingUtils_js_1.default.getIntersectionPointWithSingleModel(this.canvas.clientWidth / 2, this.canvas.clientHeight / 2, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
16421
+ if (!center || center.length < 3) {
16422
+ return { deltaX, deltaY };
16423
+ }
16424
+ const centerVec = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), gl_matrix_1.vec3.fromValues(center[0], center[1], center[2]));
16425
+ const northAxis = gl_matrix_1.vec3.fromValues(0, 0, 1);
16426
+ const eastVec = gl_matrix_1.vec3.cross(gl_matrix_1.vec3.create(), northAxis, centerVec);
16427
+ if (gl_matrix_1.vec3.length(eastVec) < 1e-6) {
16428
+ gl_matrix_1.vec3.set(eastVec, 1, 0, 0);
16429
+ }
16430
+ else {
16431
+ gl_matrix_1.vec3.normalize(eastVec, eastVec);
16432
+ }
16433
+ const northProjection = gl_matrix_1.vec3.scale(gl_matrix_1.vec3.create(), centerVec, gl_matrix_1.vec3.dot(northAxis, centerVec));
16434
+ const northVec = gl_matrix_1.vec3.subtract(gl_matrix_1.vec3.create(), northAxis, northProjection);
16435
+ if (gl_matrix_1.vec3.length(northVec) < 1e-6) {
16436
+ gl_matrix_1.vec3.cross(northVec, centerVec, eastVec);
16437
+ }
16438
+ gl_matrix_1.vec3.normalize(northVec, northVec);
16439
+ const eastScreen = this.projectModelDirectionToScreen(centerVec, eastVec);
16440
+ const northScreen = this.projectModelDirectionToScreen(centerVec, northVec);
16441
+ if (!eastScreen || !northScreen) {
16442
+ return { deltaX, deltaY };
16443
+ }
16444
+ let nextDeltaX = deltaX;
16445
+ let nextDeltaY = deltaY;
16446
+ if (lockEastWest) {
16447
+ const amount = nextDeltaX * eastScreen.x + nextDeltaY * eastScreen.y;
16448
+ nextDeltaX -= amount * eastScreen.x;
16449
+ nextDeltaY -= amount * eastScreen.y;
16450
+ }
16451
+ if (lockNorthSouth) {
16452
+ const amount = nextDeltaX * northScreen.x + nextDeltaY * northScreen.y;
16453
+ nextDeltaX -= amount * northScreen.x;
16454
+ nextDeltaY -= amount * northScreen.y;
16455
+ }
16456
+ return {
16457
+ deltaX: nextDeltaX,
16458
+ deltaY: nextDeltaY,
16459
+ };
16460
+ }
16461
+ projectModelDirectionToScreen(centerModel, directionModel) {
16462
+ const offsetModel = gl_matrix_1.vec3.scaleAndAdd(gl_matrix_1.vec3.create(), centerModel, directionModel, 0.01);
16463
+ const centerScreen = this.projectModelPointToScreen(centerModel);
16464
+ const offsetScreen = this.projectModelPointToScreen(offsetModel);
16465
+ if (!centerScreen || !offsetScreen) {
16466
+ return null;
16467
+ }
16468
+ const x = offsetScreen.x - centerScreen.x;
16469
+ const y = offsetScreen.y - centerScreen.y;
16470
+ const len = Math.hypot(x, y);
16471
+ if (len < 1e-6) {
16472
+ return null;
16473
+ }
16474
+ return { x: x / len, y: y / len };
16475
+ }
16476
+ projectModelPointToScreen(pointModel) {
16477
+ const vMatrix = this._camera.getCameraMatrix();
16478
+ const mMatrix = this._healpixGrid.getModelMatrix();
16479
+ const mvMatrix = gl_matrix_1.mat4.create();
16480
+ const mvpMatrix = gl_matrix_1.mat4.create();
16481
+ gl_matrix_1.mat4.multiply(mvMatrix, vMatrix, mMatrix);
16482
+ gl_matrix_1.mat4.multiply(mvpMatrix, this._perspectiveMatrixManager.pMatrix, mvMatrix);
16483
+ const clip = gl_matrix_1.vec4.fromValues(pointModel[0], pointModel[1], pointModel[2], 1);
16484
+ gl_matrix_1.vec4.transformMat4(clip, clip, mvpMatrix);
16485
+ if (Math.abs(clip[3]) < 1e-6) {
16486
+ return null;
16487
+ }
16488
+ return {
16489
+ x: clip[0] / clip[3],
16490
+ y: -(clip[1] / clip[3]),
16491
+ };
16492
+ }
16493
+ enforceAstronomicalRotationLocks() {
16494
+ if (this.lockedEastWestRaDeg == null && this.lockedNorthSouthDecDeg == null) {
16495
+ return false;
16496
+ }
16497
+ const center = this.updateCentralPoint();
16498
+ if (!center) {
16499
+ return false;
16500
+ }
16501
+ const nextRa = this.lockedEastWestRaDeg ?? center.astroDeg.ra;
16502
+ const nextDec = this.lockedNorthSouthDecDeg ?? center.astroDeg.dec;
16503
+ const needsCorrection = Math.abs(nextRa - center.astroDeg.ra) > 1e-6 ||
16504
+ Math.abs(nextDec - center.astroDeg.dec) > 1e-6;
16505
+ if (!needsCorrection) {
16506
+ return false;
16507
+ }
16508
+ this._camera.goTo(nextRa, nextDec);
16509
+ this._perspectiveMatrixManager.computePerspectiveMatrix(this.canvas, this._camera, Config_js_1.bootSetup.camera_fov_deg, Config_js_1.bootSetup.camera_near_plane, Global_js_1.default.insideSphere);
16510
+ this.updateCentralPoint();
16511
+ return true;
16512
+ }
16513
+ enforceCameraNorthUp() {
16514
+ if (!this.keepCameraNorthUp) {
16515
+ return false;
16516
+ }
16517
+ const center = this.updateCentralPoint();
16518
+ if (!center) {
16519
+ return false;
16520
+ }
16521
+ this._camera.goTo(center.astroDeg.ra, center.astroDeg.dec);
16522
+ this._perspectiveMatrixManager.computePerspectiveMatrix(this.canvas, this._camera, Config_js_1.bootSetup.camera_fov_deg, Config_js_1.bootSetup.camera_near_plane, Global_js_1.default.insideSphere);
16523
+ this.updateCentralPoint();
16524
+ return true;
16525
+ }
16232
16526
  emitCameraChanged(reason) {
16233
16527
  // avoid dispatch before scene is ready
16234
16528
  if (!this._activeHiPS)
@@ -16345,8 +16639,9 @@ class AstroSphere {
16345
16639
  // Rotation deltas – either use client-space or local-space, but be consistent
16346
16640
  const deltaX = ((newX - (this.lastMouseX ?? newX)) * Math.PI) / canvas.width;
16347
16641
  const deltaY = ((newY - (this.lastMouseY ?? newY)) * Math.PI) / canvas.height;
16348
- this.inertiaX += 0.1 * deltaX;
16349
- this.inertiaY += 0.1 * deltaY;
16642
+ const filteredDelta = this.filterRotationDeltaByAstroLocks(deltaX, deltaY);
16643
+ this.inertiaX += 0.1 * filteredDelta.deltaX;
16644
+ this.inertiaY += 0.1 * filteredDelta.deltaY;
16350
16645
  this.updateCentralPoint();
16351
16646
  }
16352
16647
  else {
@@ -16498,12 +16793,17 @@ class AstroSphere {
16498
16793
  this._activeBaseLayer = 'hips';
16499
16794
  }
16500
16795
  activateXYZ(config) {
16501
- this._activeXYZ = new XYZLayer_js_1.XYZLayer(config, this._webgl);
16796
+ this.activateXYZ2(new XYZMapDescriptor_js_1.XYZMapDescriptor(config.name ?? 'XYZ Earth2 Layer', config.urlTemplate, config.minZoom ?? 0, config.maxZoom ?? 8, config.segmentsPerSide ?? 48, config.maxCachedTiles ?? 384, 8, config.urlResolver));
16797
+ this._activeBaseLayer = 'xyz';
16798
+ }
16799
+ activateXYZ2(config) {
16800
+ this._activeXYZ2 = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, config, this._webgl);
16502
16801
  this._activeBaseLayer = 'xyz';
16503
16802
  }
16504
16803
  activateWMTS(config) {
16505
16804
  const adapter = new WMTSAdapter_js_1.WMTSAdapter(config);
16506
- this._activeXYZ = new XYZLayer_js_1.XYZLayer(adapter.toXYZLayerConfig(), this._webgl);
16805
+ const xyzConfig = adapter.toXYZLayerConfig();
16806
+ this._activeXYZ2 = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, new XYZMapDescriptor_js_1.XYZMapDescriptor(config.layer ? `WMTS ${config.layer}` : 'WMTS Earth2 Layer', xyzConfig.urlTemplate, xyzConfig.minZoom ?? 0, xyzConfig.maxZoom ?? 8, xyzConfig.segmentsPerSide ?? 48, xyzConfig.maxCachedTiles ?? 384, 8, xyzConfig.urlResolver), this._webgl);
16507
16807
  this._activeBaseLayer = 'xyz';
16508
16808
  }
16509
16809
  // Catalogue section
@@ -16538,7 +16838,39 @@ class AstroSphere {
16538
16838
  goTo(raDeg, decDeg) {
16539
16839
  this._camera.goTo(raDeg, decDeg);
16540
16840
  }
16841
+ getActiveCoordinateMode() {
16842
+ if (this._activeBaseLayer === 'xyz') {
16843
+ return 'lonlat';
16844
+ }
16845
+ if (this._activeBaseLayer === 'hips' && this._activeHiPS?.isGalacticHips) {
16846
+ return 'galactic';
16847
+ }
16848
+ return 'equatorial';
16849
+ }
16850
+ resetAxesOrientation() {
16851
+ const center = this.updateCentralPoint();
16852
+ if (!center)
16853
+ return;
16854
+ this.inertiaX = 0;
16855
+ this.inertiaY = 0;
16856
+ this._camera.goTo(center.astroDeg.ra, center.astroDeg.dec);
16857
+ this._perspectiveMatrixManager.computePerspectiveMatrix(this.canvas, this._camera, Config_js_1.bootSetup.camera_fov_deg, Config_js_1.bootSetup.camera_near_plane, Global_js_1.default.insideSphere);
16858
+ this.updateCentralPoint();
16859
+ this._cameraStatusChanged = true;
16860
+ }
16861
+ setKeepCameraNorthUp(enabled) {
16862
+ this.keepCameraNorthUp = enabled;
16863
+ if (enabled) {
16864
+ this.resetAxesOrientation();
16865
+ }
16866
+ }
16867
+ isKeepCameraNorthUp() {
16868
+ return this.keepCameraNorthUp;
16869
+ }
16541
16870
  getFoV() {
16871
+ if (this._activeBaseLayer === 'xyz' && this._activeXYZ2) {
16872
+ return this._activeXYZ2.getFoV();
16873
+ }
16542
16874
  return this.fov;
16543
16875
  }
16544
16876
  getFoVPolygon() {
@@ -16624,10 +16956,11 @@ class AstroSphere {
16624
16956
  // return null
16625
16957
  }
16626
16958
  changeColorMap(cm) {
16627
- if (!this._activeHiPS)
16959
+ if (!this._activeHiPS && !this._activeXYZ2)
16628
16960
  return;
16629
16961
  this._selectedColorMap = cm;
16630
16962
  this._activeHiPS?.changeColorMap(cm);
16963
+ this._activeXYZ2?.changeColorMap(cm);
16631
16964
  }
16632
16965
  prevFov = 0;
16633
16966
  prevCentralRaDeg = null;
@@ -16636,12 +16969,36 @@ class AstroSphere {
16636
16969
  return this._activeHiPS;
16637
16970
  }
16638
16971
  get activeXYZ() {
16639
- return this._activeXYZ;
16972
+ return this._activeXYZ2;
16973
+ }
16974
+ isLonLatGridVisible() {
16975
+ return this._activeXYZ2?.isLonLatGridVisible() ?? false;
16976
+ }
16977
+ toggleLonLatGrid() {
16978
+ return this._activeXYZ2?.toggleLonLatGrid() ?? false;
16979
+ }
16980
+ setEastWestRotationLocked(locked) {
16981
+ this._camera.setRotationLock({ y: locked });
16982
+ if (locked)
16983
+ this.inertiaX = 0;
16984
+ this.lockedEastWestRaDeg = locked ? this.updateCentralPoint()?.astroDeg.ra ?? null : null;
16985
+ }
16986
+ isEastWestRotationLocked() {
16987
+ return this._camera.isRotationLockedY();
16988
+ }
16989
+ setNorthSouthRotationLocked(locked) {
16990
+ this._camera.setRotationLock({ x: locked });
16991
+ if (locked)
16992
+ this.inertiaY = 0;
16993
+ this.lockedNorthSouthDecDeg = locked ? this.updateCentralPoint()?.astroDeg.dec ?? null : null;
16994
+ }
16995
+ isNorthSouthRotationLocked() {
16996
+ return this._camera.isRotationLockedX();
16640
16997
  }
16641
16998
  getXYZDebugStats() {
16642
16999
  return {
16643
17000
  activeBaseLayer: this._activeBaseLayer,
16644
- layer: this._activeXYZ?.getDebugStats() ?? null,
17001
+ layer: this._activeXYZ2?.getDebugStats() ?? null,
16645
17002
  requests: XYZTileRequestScheduler_js_1.xyzTileRequestScheduler.getDebugStats(),
16646
17003
  };
16647
17004
  }
@@ -16650,7 +17007,7 @@ class AstroSphere {
16650
17007
  return;
16651
17008
  if (!this._webgl)
16652
17009
  return;
16653
- if (!this._activeHiPS && !this._activeXYZ)
17010
+ if (!this._activeHiPS && !this._activeXYZ2)
16654
17011
  return;
16655
17012
  if (!this._healpixGrid || Object.keys(this._healpixGrid).length === 0)
16656
17013
  return;
@@ -16687,12 +17044,17 @@ class AstroSphere {
16687
17044
  // Rotation inertia
16688
17045
  if (this.mouseDown || Math.abs(this.inertiaX) > 0.02 || Math.abs(this.inertiaY) > 0.02) {
16689
17046
  cameraRotated = true;
16690
- THETA = this.inertiaY;
16691
- PHI = this.inertiaX;
16692
- this.inertiaX *= 0.95;
16693
- this.inertiaY *= 0.95;
17047
+ const filteredInertia = this.filterRotationDeltaByAstroLocks(this.inertiaX, this.inertiaY);
17048
+ PHI = filteredInertia.deltaX;
17049
+ THETA = filteredInertia.deltaY;
17050
+ this.inertiaX = filteredInertia.deltaX * 0.95;
17051
+ this.inertiaY = filteredInertia.deltaY * 0.95;
16694
17052
  this._camera.rotate(PHI, THETA);
16695
17053
  this._perspectiveMatrixManager.computePerspectiveMatrix(canvas, this._camera, Config_js_1.bootSetup.camera_fov_deg, Config_js_1.bootSetup.camera_near_plane, Global_js_1.default.insideSphere);
17054
+ const lockCorrected = this.enforceAstronomicalRotationLocks();
17055
+ if (!lockCorrected) {
17056
+ this.enforceCameraNorthUp();
17057
+ }
16696
17058
  }
16697
17059
  else {
16698
17060
  this.inertiaY = 0;
@@ -16751,7 +17113,7 @@ class AstroSphere {
16751
17113
  this._activeHiPS?.draw(skyEntityDrawInput);
16752
17114
  }
16753
17115
  if (this._activeBaseLayer === 'xyz') {
16754
- this._activeXYZ?.draw(skyEntityDrawInput);
17116
+ this._activeXYZ2?.draw(skyEntityDrawInput);
16755
17117
  }
16756
17118
  this._healpixGrid.draw(skyEntityDrawInput);
16757
17119
  this._equatorialGrid.draw(skyEntityDrawInput);
@@ -16773,14 +17135,14 @@ class AstroSphere {
16773
17135
  });
16774
17136
  }
16775
17137
  this.activeCatalogues.forEach(cat => {
16776
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ?? this._activeXYZ?.getModelMatrix();
17138
+ const activeModelMatrix = this._activeHiPS?.getModelMatrix() ?? this._activeXYZ2?.getModelMatrix();
16777
17139
  if (activeModelMatrix) {
16778
17140
  cat.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
16779
17141
  }
16780
17142
  });
16781
17143
  this.emitHoveredSourceIfChanged();
16782
17144
  this.activeFootprintSets.forEach(fst => {
16783
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ?? this._activeXYZ?.getModelMatrix();
17145
+ const activeModelMatrix = this._activeHiPS?.getModelMatrix() ?? this._activeXYZ2?.getModelMatrix();
16784
17146
  if (activeModelMatrix) {
16785
17147
  fst.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
16786
17148
  }
@@ -16819,11 +17181,23 @@ exports["default"] = AstroSphere;
16819
17181
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
16820
17182
 
16821
17183
 
16822
- /**
16823
- * @author Fabrizio Giordano (Fab)
17184
+ /*
17185
+ * AstroViewer
17186
+ * Copyright (C) Fabrizio Giordano
17187
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17188
+ *
17189
+ * This file is part of AstroViewer.
17190
+ * AstroViewer is distributed under a dual-license model.
17191
+ * Commercial use requires a separate commercial license.
17192
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17193
+ *
17194
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
16824
17195
  */
16825
17196
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16826
17197
  exports.AbstractSkyEntity = void 0;
17198
+ /**
17199
+ * @author Fabrizio Giordano (Fab)
17200
+ */
16827
17201
  const gl_matrix_1 = __webpack_require__(1961);
16828
17202
  const HiPSShaderProgram_js_1 = __webpack_require__(7786);
16829
17203
  class AbstractSkyEntity {
@@ -16973,6 +17347,18 @@ exports.AbstractSkyEntity = AbstractSkyEntity;
16973
17347
  /***/ 5087:
16974
17348
  /***/ ((__unused_webpack_module, exports) => {
16975
17349
 
17350
+ /*
17351
+ * AstroViewer
17352
+ * Copyright (C) Fabrizio Giordano
17353
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17354
+ *
17355
+ * This file is part of AstroViewer.
17356
+ * AstroViewer is distributed under a dual-license model.
17357
+ * Commercial use requires a separate commercial license.
17358
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17359
+ *
17360
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
17361
+ */
16976
17362
  // HiPSDescriptor.ts
16977
17363
 
16978
17364
  Object.defineProperty(exports, "__esModule", ({ value: true }));
@@ -17115,97 +17501,100 @@ exports.HiPSDescriptor = HiPSDescriptor;
17115
17501
  /***/ ((__unused_webpack_module, exports) => {
17116
17502
 
17117
17503
 
17118
- /**
17119
- * @author Fabrizio Giordano (Fab)
17120
- * @param in_radius - number
17121
- * @param in_gl - GL context
17122
- * @param in_position - array of double e.g. [0.0, 0.0, 0.0]
17504
+ /*
17505
+ * AstroViewer
17506
+ * Copyright (C) Fabrizio Giordano
17507
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17508
+ *
17509
+ * This file is part of AstroViewer.
17510
+ * AstroViewer is distributed under a dual-license model.
17511
+ * Commercial use requires a separate commercial license.
17512
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17513
+ *
17514
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
17123
17515
  */
17124
17516
  Object.defineProperty(exports, "__esModule", ({ value: true }));
17125
17517
  class GridTextHelper {
17126
- _divEqContainerElement;
17127
- _divHPXContainerElement;
17128
- _divSets;
17129
- _divSetNdx;
17130
- constructor() {
17131
- this._divEqContainerElement = document.querySelector('#gridcoords');
17132
- this._divHPXContainerElement = document.querySelector('#gridhpx');
17133
- this._divSetNdx = 0;
17134
- this._divSets = [];
17518
+ static layers = new Map();
17519
+ layer;
17520
+ constructor(layer = 'equatorial') {
17521
+ this.layer = layer;
17522
+ GridTextHelper.getLayerState(layer);
17135
17523
  }
17136
17524
  initHtml() {
17137
- // Kept for API parity; nothing required here with current logic.
17525
+ GridTextHelper.getLayerState(this.layer);
17138
17526
  }
17139
- resetDivSets() {
17140
- // Hide remaining divs and reset index
17141
- for (; this._divSetNdx < this._divSets.length; ++this._divSetNdx) {
17142
- this._divSets[this._divSetNdx].style.display = 'none';
17527
+ resetDivSets(layer = this.layer) {
17528
+ const state = GridTextHelper.getLayerState(layer);
17529
+ for (; state.divSetNdx < state.divSets.length; ++state.divSetNdx) {
17530
+ state.divSets[state.divSetNdx].style.display = 'none';
17143
17531
  }
17144
- this._divSetNdx = 0;
17532
+ state.divSetNdx = 0;
17145
17533
  }
17146
- /**
17147
- * Add / reuse a floating label for HPX coordinates
17148
- */
17149
17534
  addHPXDivSet(msg, x, y) {
17150
- let divSet = this._divSets[this._divSetNdx++];
17151
- // Create on demand
17535
+ this.addLabel('healpix', msg, x + 25, y, 'hpx');
17536
+ }
17537
+ addEqDivSet(msg, x, y, type) {
17538
+ this.addLabel('equatorial', msg, type === 'ra' ? x + 25 : x, type === 'ra' ? y : y + 25, type);
17539
+ }
17540
+ addLonLatDivSet(msg, x, y, type) {
17541
+ this.addLabel('lonlat', msg, type === 'lon' ? x + 25 : x, type === 'lon' ? y : y + 25, type);
17542
+ }
17543
+ addLabel(layer, msg, x, y, kind) {
17544
+ const state = GridTextHelper.getLayerState(layer);
17545
+ if (!state.container)
17546
+ return;
17547
+ let divSet = state.divSets[state.divSetNdx++];
17152
17548
  if (!divSet) {
17153
17549
  const div = document.createElement('div');
17154
17550
  const textNode = document.createTextNode('');
17155
- div.className = 'floating-div-ra'; // style like RA tags
17156
17551
  div.appendChild(textNode);
17157
- if (!this._divHPXContainerElement) {
17158
- this._divHPXContainerElement = document.querySelector('#gridhpx');
17159
- }
17160
- if (!this._divHPXContainerElement) {
17161
- // If container is still missing, abort gracefully
17162
- return;
17163
- }
17164
- this._divHPXContainerElement.appendChild(div);
17552
+ state.container.appendChild(div);
17165
17553
  divSet = { div, textNode, style: div.style };
17166
- this._divSets.push(divSet);
17554
+ state.divSets.push(divSet);
17167
17555
  }
17168
- // Show & position
17556
+ divSet.div.className = this.classNameForKind(kind);
17169
17557
  divSet.style.display = 'block';
17170
- divSet.style.left = `${Math.floor(x + 25)}px`;
17558
+ divSet.style.left = `${Math.floor(x)}px`;
17171
17559
  divSet.style.top = `${Math.floor(y)}px`;
17172
17560
  divSet.textNode.nodeValue = msg;
17173
17561
  }
17174
- /**
17175
- * Add / reuse a floating label for Equatorial coords
17176
- * @param type 'ra' or 'dec'
17177
- */
17178
- addEqDivSet(msg, x, y, type) {
17179
- let divSet = this._divSets[this._divSetNdx++];
17180
- if (!divSet) {
17181
- const div = document.createElement('div');
17182
- const textNode = document.createTextNode('');
17183
- div.className = type === 'ra' ? 'floating-div-ra' : 'floating-div-dec';
17184
- div.appendChild(textNode);
17185
- if (!this._divEqContainerElement) {
17186
- this._divEqContainerElement = document.querySelector('#gridcoords');
17187
- }
17188
- if (!this._divEqContainerElement) {
17189
- // If container is still missing, abort gracefully
17190
- return;
17191
- }
17192
- this._divEqContainerElement.appendChild(div);
17193
- divSet = { div, textNode, style: div.style };
17194
- this._divSets.push(divSet);
17562
+ classNameForKind(kind) {
17563
+ switch (kind) {
17564
+ case 'dec':
17565
+ return 'floating-div-dec';
17566
+ case 'lat':
17567
+ return 'floating-div-lat';
17568
+ case 'lon':
17569
+ return 'floating-div-lon';
17570
+ case 'hpx':
17571
+ case 'ra':
17572
+ default:
17573
+ return 'floating-div-ra';
17195
17574
  }
17196
- divSet.style.display = 'block';
17197
- if (type === 'ra') {
17198
- divSet.style.left = `${Math.floor(x + 25)}px`;
17199
- divSet.style.top = `${Math.floor(y)}px`;
17575
+ }
17576
+ static getLayerState(layer) {
17577
+ const current = GridTextHelper.layers.get(layer);
17578
+ if (current) {
17579
+ if (!current.container)
17580
+ current.container = GridTextHelper.resolveContainer(layer);
17581
+ return current;
17200
17582
  }
17201
- else {
17202
- divSet.style.left = `${Math.floor(x)}px`;
17203
- divSet.style.top = `${Math.floor(y + 25)}px`;
17583
+ const state = {
17584
+ container: GridTextHelper.resolveContainer(layer),
17585
+ divSets: [],
17586
+ divSetNdx: 0,
17587
+ };
17588
+ GridTextHelper.layers.set(layer, state);
17589
+ return state;
17590
+ }
17591
+ static resolveContainer(layer) {
17592
+ if (layer === 'healpix') {
17593
+ return document.querySelector('#gridhpx');
17204
17594
  }
17205
- divSet.textNode.nodeValue = msg;
17595
+ return document.querySelector('#gridcoords');
17206
17596
  }
17207
17597
  }
17208
- // export const gridTextHelper = new GridTextHelper();
17209
17598
  exports["default"] = GridTextHelper;
17210
17599
 
17211
17600
 
@@ -17215,6 +17604,18 @@ exports["default"] = GridTextHelper;
17215
17604
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
17216
17605
 
17217
17606
 
17607
+ /*
17608
+ * AstroViewer
17609
+ * Copyright (C) Fabrizio Giordano
17610
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17611
+ *
17612
+ * This file is part of AstroViewer.
17613
+ * AstroViewer is distributed under a dual-license model.
17614
+ * Commercial use requires a separate commercial license.
17615
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17616
+ *
17617
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
17618
+ */
17218
17619
  Object.defineProperty(exports, "__esModule", ({ value: true }));
17219
17620
  exports.MetadataManager = void 0;
17220
17621
  const MetadataColumn_js_1 = __webpack_require__(1072);
@@ -17342,6 +17743,18 @@ exports.MetadataManager = MetadataManager;
17342
17743
  /***/ ((__unused_webpack_module, exports) => {
17343
17744
 
17344
17745
 
17746
+ /*
17747
+ * AstroViewer
17748
+ * Copyright (C) Fabrizio Giordano
17749
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17750
+ *
17751
+ * This file is part of AstroViewer.
17752
+ * AstroViewer is distributed under a dual-license model.
17753
+ * Commercial use requires a separate commercial license.
17754
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17755
+ *
17756
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
17757
+ */
17345
17758
  Object.defineProperty(exports, "__esModule", ({ value: true }));
17346
17759
  exports.xyzTileRequestScheduler = exports.XYZTileRequestScheduler = exports.XYZTileRequestError = void 0;
17347
17760
  class XYZTileRequestError extends Error {
@@ -17420,9 +17833,8 @@ class XYZTileRequestScheduler {
17420
17833
  pump() {
17421
17834
  while (this._activeCount < this._maxConcurrent && this._queue.length > 0) {
17422
17835
  const item = this._queue.shift();
17423
- if (!item) {
17836
+ if (!item)
17424
17837
  return;
17425
- }
17426
17838
  const hostCooldown = this.getHostCooldown(item.url);
17427
17839
  const now = Date.now();
17428
17840
  if (hostCooldown > now) {
@@ -17515,6 +17927,18 @@ exports.xyzTileRequestScheduler = new XYZTileRequestScheduler();
17515
17927
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
17516
17928
 
17517
17929
 
17930
+ /*
17931
+ * AstroViewer
17932
+ * Copyright (C) Fabrizio Giordano
17933
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17934
+ *
17935
+ * This file is part of AstroViewer.
17936
+ * AstroViewer is distributed under a dual-license model.
17937
+ * Commercial use requires a separate commercial license.
17938
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17939
+ *
17940
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
17941
+ */
17518
17942
  Object.defineProperty(exports, "__esModule", ({ value: true }));
17519
17943
  exports.TerraPointSetGL = void 0;
17520
17944
  const CatalogueGL_js_1 = __webpack_require__(1232);
@@ -17526,51 +17950,268 @@ exports.TerraPointSetGL = TerraPointSetGL;
17526
17950
 
17527
17951
  /***/ }),
17528
17952
 
17529
- /***/ 5947:
17530
- /***/ ((__unused_webpack_module, exports) => {
17953
+ /***/ 5803:
17954
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
17531
17955
 
17532
17956
 
17533
- // ShaderManager.ts
17957
+ /*
17958
+ * AstroViewer
17959
+ * Copyright (C) Fabrizio Giordano
17960
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
17961
+ *
17962
+ * This file is part of AstroViewer.
17963
+ * AstroViewer is distributed under a dual-license model.
17964
+ * Commercial use requires a separate commercial license.
17965
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
17966
+ *
17967
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
17968
+ */
17534
17969
  Object.defineProperty(exports, "__esModule", ({ value: true }));
17535
- class ShaderManager {
17536
- static catalogueVS() {
17537
- return `#version 300 es
17538
- in vec4 aCatPosition;
17539
- in float a_selected;
17540
- in float a_pointsize;
17541
- in float a_brightness;
17542
-
17543
- out float v_selected;
17544
- out float v_brightness;
17545
- out lowp vec4 vColor; // not used
17546
-
17547
- uniform mat4 uPMatrix;
17548
- uniform mat4 uMVMatrix;
17549
-
17550
- void main() {
17551
-
17552
- gl_Position = (uPMatrix * uMVMatrix * aCatPosition);
17553
- gl_PointSize = a_pointsize;
17554
- v_selected = a_selected;
17555
- v_brightness = a_brightness;
17556
- }`;
17970
+ exports.SphereFoV = void 0;
17971
+ const gl_matrix_1 = __webpack_require__(1961);
17972
+ const Utils_js_1 = __webpack_require__(7930);
17973
+ class SphereFoV {
17974
+ static MIN_FOV_DEG = 1e-6;
17975
+ fovXDeg = 180;
17976
+ fovYDeg = 180;
17977
+ ratio = 0;
17978
+ _minFoV = 180;
17979
+ _webgl;
17980
+ _lastModel = null;
17981
+ _lastCamera = null;
17982
+ constructor(webgl) {
17983
+ this._webgl = webgl;
17557
17984
  }
17558
- static catalogueFS() {
17559
- return `#version 300 es
17560
- precision mediump float;
17561
-
17562
- #ifdef GL_OES_standard_derivatives
17563
- #extension GL_OES_standard_derivatives : enable
17564
- #endif
17565
-
17566
- // https://www.desultoryquest.com/blog/drawing-anti-aliased-circular-points-using-opengl-slash-webgl/
17567
-
17568
- // precision mediump float;
17569
-
17570
- in float v_selected;
17571
- in float v_brightness;
17572
-
17573
- uniform vec4 u_fragcolor;
17985
+ getFoV(insideSphere, model, camera, pMatrix) {
17986
+ this._lastModel = model;
17987
+ this._lastCamera = camera;
17988
+ const canvas = this._webgl.canvas;
17989
+ if (!canvas) {
17990
+ this.fovXDeg = 180;
17991
+ this.fovYDeg = 180;
17992
+ this._minFoV = this.minFoV;
17993
+ return this;
17994
+ }
17995
+ const rect = canvas.getBoundingClientRect();
17996
+ const canvasWidth = rect.width;
17997
+ const canvasHeight = rect.height;
17998
+ this.fovXDeg = this.computeAngle(0, canvasHeight / 2, insideSphere, model, camera, pMatrix).angleDeg;
17999
+ this.fovYDeg = this.computeAngle(canvasWidth / 2, 0, insideSphere, model, camera, pMatrix).angleDeg;
18000
+ this._minFoV = this.minFoV;
18001
+ this.ratio = this.computeRatio(camera);
18002
+ return this;
18003
+ }
18004
+ computeRatio(camera) {
18005
+ const pos = camera.getCameraPosition();
18006
+ const distanceFromCenter = Math.sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]);
18007
+ return distanceFromCenter / this.fovYDeg;
18008
+ }
18009
+ get minFoV() {
18010
+ const minFov = this.fovYDeg <= this.fovXDeg ? this.fovYDeg : this.fovXDeg;
18011
+ this._minFoV = Math.max(minFov, SphereFoV.MIN_FOV_DEG);
18012
+ return this._minFoV;
18013
+ }
18014
+ get xFoV() {
18015
+ return this.fovXDeg;
18016
+ }
18017
+ get yFoV() {
18018
+ return this.fovYDeg;
18019
+ }
18020
+ computeDistanceFromAngle(angleDeg) {
18021
+ return angleDeg * this.ratio;
18022
+ }
18023
+ changeMinFov(deg) {
18024
+ if (this.fovYDeg <= this.fovXDeg) {
18025
+ this.fovYDeg = deg;
18026
+ }
18027
+ else {
18028
+ this.fovXDeg = deg;
18029
+ }
18030
+ this.minFoV;
18031
+ }
18032
+ computeCameraPositionForMinFoV(targetMinFoVDeg) {
18033
+ return this.computeCameraPositionForFoV(targetMinFoVDeg);
18034
+ }
18035
+ computeCameraPositionForFoV(targetFoVDeg) {
18036
+ return this.computeCameraPositionForAngularDiameter(targetFoVDeg);
18037
+ }
18038
+ computeCameraPositionForAngularDiameter(targetAngularDiameterDeg) {
18039
+ if (!this._lastModel || !this._lastCamera) {
18040
+ return [0, 0, 0];
18041
+ }
18042
+ const eps = 1e-6;
18043
+ const clamped = Math.max(eps, Math.min(180 - eps, targetAngularDiameterDeg));
18044
+ const halfRad = (clamped * Math.PI) / 360.0;
18045
+ const sinHalf = Math.sin(halfRad);
18046
+ if (sinHalf <= 0) {
18047
+ return [0, 0, 0];
18048
+ }
18049
+ const model = this._lastModel;
18050
+ const camera = this._lastCamera;
18051
+ const targetDistance = Math.max(model.radius / sinHalf, model.radius + 1e-4);
18052
+ const camPos = camera.getCameraPosition();
18053
+ const direction = gl_matrix_1.vec3.fromValues(camPos[0] - model.center[0], camPos[1] - model.center[1], camPos[2] - model.center[2]);
18054
+ if (gl_matrix_1.vec3.length(direction) < eps) {
18055
+ gl_matrix_1.vec3.set(direction, 0, 0, 1);
18056
+ }
18057
+ else {
18058
+ gl_matrix_1.vec3.normalize(direction, direction);
18059
+ }
18060
+ return [
18061
+ model.center[0] + direction[0] * targetDistance,
18062
+ model.center[1] + direction[1] * targetDistance,
18063
+ model.center[2] + direction[2] * targetDistance,
18064
+ ];
18065
+ }
18066
+ computeAngle(canvasX, canvasY, insideSphere, model, camera, pMatrix) {
18067
+ const canvas = this._webgl.canvas;
18068
+ const rect = canvas.getBoundingClientRect();
18069
+ const centerHit = this.getIntersectionPointWithModel(rect.width / 2, rect.height / 2, model, camera, pMatrix);
18070
+ const edgeHit = this.getIntersectionPointWithModel(canvasX, canvasY, model, camera, pMatrix);
18071
+ if (!centerHit || !edgeHit) {
18072
+ return { angleDeg: 180, distance: -1 };
18073
+ }
18074
+ const angleDeg = 2 * this.computeAngularDistanceDeg(centerHit.point, edgeHit.point);
18075
+ return {
18076
+ angleDeg: insideSphere ? 360 - angleDeg : angleDeg,
18077
+ distance: edgeHit.distance,
18078
+ };
18079
+ }
18080
+ computeAngularDistanceDeg(a, b) {
18081
+ const aNorm = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), a);
18082
+ const bNorm = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), b);
18083
+ const dot = gl_matrix_1.vec3.dot(aNorm, bNorm);
18084
+ const clamped = Math.min(1, Math.max(-1, dot));
18085
+ return (0, Utils_js_1.radToDeg)(Math.acos(clamped));
18086
+ }
18087
+ getIntersectionPointWithModel(mouseX, mouseY, model, camera, pMatrix) {
18088
+ const rayWorld = this.getRayFromMouse(mouseX, mouseY, pMatrix, camera.getCameraMatrix());
18089
+ const distance = this.raySphere(camera.getCameraPosition(), rayWorld, model);
18090
+ if (distance < 0) {
18091
+ return null;
18092
+ }
18093
+ const worldHit = gl_matrix_1.vec3.create();
18094
+ gl_matrix_1.vec3.scale(worldHit, rayWorld, distance);
18095
+ gl_matrix_1.vec3.add(worldHit, camera.getCameraPosition(), worldHit);
18096
+ const worldHit4 = [worldHit[0], worldHit[1], worldHit[2], 1.0];
18097
+ const modelHit4 = [0, 0, 0, 0];
18098
+ this.mat4MultiplyVec4(model.getModelMatrixInverse(), worldHit4, modelHit4);
18099
+ return {
18100
+ point: gl_matrix_1.vec3.fromValues(modelHit4[0], modelHit4[1], modelHit4[2]),
18101
+ distance,
18102
+ };
18103
+ }
18104
+ getRayFromMouse(mouseX, mouseY, pMatrix, vMatrix) {
18105
+ const gl = this._webgl;
18106
+ const canvas = gl.canvas;
18107
+ const rect = canvas.getBoundingClientRect();
18108
+ const x = (2.0 * mouseX) / rect.width - 1.0;
18109
+ const y = 1.0 - (2.0 * mouseY) / rect.height;
18110
+ const rayClip = [x, y, -1.0, 1.0];
18111
+ const pInv = gl_matrix_1.mat4.create();
18112
+ gl_matrix_1.mat4.invert(pInv, pMatrix);
18113
+ const rayEye4 = [0, 0, 0, 0];
18114
+ this.mat4MultiplyVec4(pInv, rayClip, rayEye4);
18115
+ const rayEye = [rayEye4[0], rayEye4[1], -1.0, 0.0];
18116
+ const vInv = gl_matrix_1.mat4.create();
18117
+ gl_matrix_1.mat4.invert(vInv, vMatrix);
18118
+ const rayWorld4 = [0, 0, 0, 0];
18119
+ this.mat4MultiplyVec4(vInv, rayEye, rayWorld4);
18120
+ const rayWorld = gl_matrix_1.vec3.fromValues(rayWorld4[0], rayWorld4[1], rayWorld4[2]);
18121
+ gl_matrix_1.vec3.normalize(rayWorld, rayWorld);
18122
+ return rayWorld;
18123
+ }
18124
+ raySphere(rayOrigWorld, rayDirectionWorld, sphere) {
18125
+ let intersectionDistance = -1;
18126
+ const L = gl_matrix_1.vec3.create();
18127
+ gl_matrix_1.vec3.subtract(L, rayOrigWorld, sphere.center);
18128
+ const b = gl_matrix_1.vec3.dot(rayDirectionWorld, L);
18129
+ const c = gl_matrix_1.vec3.dot(L, L) - sphere.radius * sphere.radius;
18130
+ const disc = b * b - c;
18131
+ if (disc > 0.0) {
18132
+ const s = Math.sqrt(disc);
18133
+ const ta = -b + s;
18134
+ const tb = -b - s;
18135
+ if (ta >= 0.0 || tb >= 0.0) {
18136
+ intersectionDistance = tb < 0.0 ? ta : Math.min(ta, tb);
18137
+ }
18138
+ }
18139
+ else if (disc === 0.0) {
18140
+ const t = -b;
18141
+ if (t >= 0.0) {
18142
+ intersectionDistance = t;
18143
+ }
18144
+ }
18145
+ return intersectionDistance;
18146
+ }
18147
+ mat4MultiplyVec4(m, v, out) {
18148
+ out[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3];
18149
+ out[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3];
18150
+ out[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3];
18151
+ out[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3];
18152
+ }
18153
+ }
18154
+ exports.SphereFoV = SphereFoV;
18155
+
18156
+
18157
+ /***/ }),
18158
+
18159
+ /***/ 5947:
18160
+ /***/ ((__unused_webpack_module, exports) => {
18161
+
18162
+
18163
+ /*
18164
+ * AstroViewer
18165
+ * Copyright (C) Fabrizio Giordano
18166
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
18167
+ *
18168
+ * This file is part of AstroViewer.
18169
+ * AstroViewer is distributed under a dual-license model.
18170
+ * Commercial use requires a separate commercial license.
18171
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
18172
+ *
18173
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
18174
+ */
18175
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18176
+ class ShaderManager {
18177
+ static catalogueVS() {
18178
+ return `#version 300 es
18179
+ in vec4 aCatPosition;
18180
+ in float a_selected;
18181
+ in float a_pointsize;
18182
+ in float a_brightness;
18183
+
18184
+ out float v_selected;
18185
+ out float v_brightness;
18186
+ out lowp vec4 vColor; // not used
18187
+
18188
+ uniform mat4 uPMatrix;
18189
+ uniform mat4 uMVMatrix;
18190
+
18191
+ void main() {
18192
+
18193
+ gl_Position = (uPMatrix * uMVMatrix * aCatPosition);
18194
+ gl_PointSize = a_pointsize;
18195
+ v_selected = a_selected;
18196
+ v_brightness = a_brightness;
18197
+ }`;
18198
+ }
18199
+ static catalogueFS() {
18200
+ return `#version 300 es
18201
+ precision mediump float;
18202
+
18203
+ #ifdef GL_OES_standard_derivatives
18204
+ #extension GL_OES_standard_derivatives : enable
18205
+ #endif
18206
+
18207
+ // https://www.desultoryquest.com/blog/drawing-anti-aliased-circular-points-using-opengl-slash-webgl/
18208
+
18209
+ // precision mediump float;
18210
+
18211
+ in float v_selected;
18212
+ in float v_brightness;
18213
+
18214
+ uniform vec4 u_fragcolor;
17574
18215
 
17575
18216
  out vec4 fragColor;
17576
18217
 
@@ -17882,6 +18523,18 @@ exports["default"] = ShaderManager;
17882
18523
  /***/ 6553:
17883
18524
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
17884
18525
 
18526
+ /*
18527
+ * AstroViewer
18528
+ * Copyright (C) Fabrizio Giordano
18529
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
18530
+ *
18531
+ * This file is part of AstroViewer.
18532
+ * AstroViewer is distributed under a dual-license model.
18533
+ * Commercial use requires a separate commercial license.
18534
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
18535
+ *
18536
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
18537
+ */
17885
18538
  /**
17886
18539
  * @author Fabrizio Giordano (Fab77)
17887
18540
  */
@@ -18025,214 +18678,86 @@ exports.Point = Point;
18025
18678
  /***/ }),
18026
18679
 
18027
18680
  /***/ 6937:
18028
- /***/ ((__unused_webpack_module, exports) => {
18681
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
18029
18682
 
18030
18683
 
18684
+ /*
18685
+ * AstroViewer
18686
+ * Copyright (C) Fabrizio Giordano
18687
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
18688
+ *
18689
+ * This file is part of AstroViewer.
18690
+ * AstroViewer is distributed under a dual-license model.
18691
+ * Commercial use requires a separate commercial license.
18692
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
18693
+ *
18694
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
18695
+ */
18696
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18697
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18698
+ };
18031
18699
  Object.defineProperty(exports, "__esModule", ({ value: true }));
18032
18700
  exports.XYZVisibleTilesManager = void 0;
18701
+ const XYZRayPickingUtils_js_1 = __importDefault(__webpack_require__(2166));
18033
18702
  class XYZVisibleTilesManager {
18034
- _provider;
18035
- constructor(provider) {
18036
- this._provider = provider;
18037
- }
18038
- selectTiles(input) {
18039
- const currentZoom = this._provider.resolveZoom(input.fovDeg ?? 180);
18040
- const coreTiles = this.orderTilesByScreenRelevance(this.buildCoreVisibleTiles(currentZoom, input), currentZoom, input.centerSphericalDeg ?? null);
18041
- const coverageTiles = this.orderTilesByScreenRelevance(this.buildCoverageTiles(currentZoom, input, coreTiles), currentZoom, input.centerSphericalDeg ?? null);
18042
- const currentTiles = [...coreTiles, ...coverageTiles];
18043
- const fallbackSeedTiles = this.buildFallbackSeedTiles(coreTiles, currentZoom, input.centerSphericalDeg ?? null);
18044
- const fallbackTiles = this.orderFallbackTiles(Array.from(this.buildFallbackMap(fallbackSeedTiles, currentZoom).values()), currentZoom, input.centerSphericalDeg ?? null);
18045
- const key = `${currentZoom}:${currentTiles.map((tile) => `${tile.x}/${tile.y}`).join('|')}`;
18046
- return {
18047
- key,
18048
- currentTiles,
18049
- fallbackTiles,
18050
- currentZoom,
18051
- coreTileCount: coreTiles.length,
18052
- coverageTileCount: coverageTiles.length,
18053
- };
18054
- }
18055
- buildCoreVisibleTiles(currentZoom, input) {
18056
- const samples = this.collectCoverageSamples(input);
18057
- if (samples.length === 0) {
18058
- return this._provider.getVisibleTilesAtZoom(currentZoom, null, [], [], 0);
18059
- }
18060
- const tiles = [];
18061
- for (const sample of samples) {
18062
- tiles.push(this._provider.tileFromSpherical(currentZoom, sample));
18063
- }
18064
- return this._provider.deduplicateTiles(tiles);
18065
- }
18066
- buildCoverageTiles(currentZoom, input, coreTiles) {
18067
- if (coreTiles.length === 0) {
18068
- return [];
18069
- }
18070
- const ring = this.getNeighborRing(currentZoom, input.fovDeg ?? 180);
18071
- if (ring <= 0) {
18072
- return [];
18073
- }
18074
- const coreSet = new Set(coreTiles.map((tile) => this.key(tile)));
18075
- const coverageTiles = [];
18076
- for (const tile of coreTiles) {
18077
- if (!this.isBoundaryTile(tile, coreSet)) {
18078
- continue;
18079
- }
18080
- const neighbors = this._provider.getNeighborTiles(tile, ring);
18081
- for (const neighbor of neighbors) {
18082
- const neighborKey = this.key(neighbor);
18083
- if (coreSet.has(neighborKey)) {
18084
- continue;
18085
- }
18086
- coverageTiles.push(neighbor);
18087
- }
18088
- }
18089
- return this._provider.deduplicateTiles(coverageTiles);
18090
- }
18091
- collectCoverageSamples(input) {
18092
- const samples = [];
18093
- if (input.centerSphericalDeg) {
18094
- samples.push(input.centerSphericalDeg);
18095
- }
18096
- for (const sample of input.viewportSphericalSamples ?? []) {
18097
- samples.push(sample);
18098
- }
18099
- const polygonSamples = this.interpolateFoVPolygon(input.fovPolygon ?? []);
18100
- for (const sample of polygonSamples) {
18101
- samples.push(sample);
18102
- }
18103
- return samples;
18104
- }
18105
- interpolateFoVPolygon(fovPolygon) {
18106
- if (fovPolygon.length === 0) {
18107
- return [];
18108
- }
18109
- const polygonSpherical = fovPolygon.map((point) => ({
18110
- phi: point.raDeg < 0 ? point.raDeg + 360 : point.raDeg,
18111
- theta: 90 - point.decDeg,
18112
- }));
18113
- const samples = [...polygonSpherical];
18114
- const segmentInterpolationCount = polygonSpherical.length >= 4 ? 3 : 1;
18115
- for (let i = 0; i < polygonSpherical.length; i++) {
18116
- const start = polygonSpherical[i];
18117
- const end = polygonSpherical[(i + 1) % polygonSpherical.length];
18118
- if (!start || !end)
18119
- continue;
18120
- const startPhi = this.normalizePhi(start.phi);
18121
- let endPhi = this.normalizePhi(end.phi);
18122
- if (Math.abs(endPhi - startPhi) > 180) {
18123
- endPhi += endPhi > startPhi ? -360 : 360;
18124
- }
18125
- for (let step = 1; step <= segmentInterpolationCount; step++) {
18126
- const t = step / (segmentInterpolationCount + 1);
18127
- const phi = this.normalizePhi(startPhi + (endPhi - startPhi) * t);
18128
- const theta = start.theta + (end.theta - start.theta) * t;
18129
- samples.push({ phi, theta });
18130
- }
18131
- }
18132
- return samples;
18133
- }
18134
- getNeighborRing(currentZoom, fovDeg) {
18135
- if (currentZoom >= 14 && fovDeg < 10) {
18136
- return 0;
18137
- }
18138
- return 1;
18139
- }
18140
- isBoundaryTile(tile, coreTileKeys) {
18141
- const directNeighbors = [
18142
- { z: tile.z, x: tile.x - 1, y: tile.y },
18143
- { z: tile.z, x: tile.x + 1, y: tile.y },
18144
- { z: tile.z, x: tile.x, y: tile.y - 1 },
18145
- { z: tile.z, x: tile.x, y: tile.y + 1 },
18146
- ];
18147
- return directNeighbors.some((neighbor) => !coreTileKeys.has(this.key(this.normalizeTile(neighbor))));
18703
+ _ancestorsMap = new Map();
18704
+ _visibleTilesMap = new Map();
18705
+ _visibleTiles = [];
18706
+ _selection = {
18707
+ key: '0:',
18708
+ currentZoom: 0,
18709
+ visibleTiles: [],
18710
+ visibleTilesMap: new Map(),
18711
+ ancestorsMap: new Map(),
18712
+ };
18713
+ get ancestorsMap() {
18714
+ return this._ancestorsMap;
18148
18715
  }
18149
- normalizeTile(tile) {
18150
- const dim = 2 ** tile.z;
18151
- return {
18152
- z: tile.z,
18153
- x: ((tile.x % dim) + dim) % dim,
18154
- y: Math.max(0, Math.min(dim - 1, tile.y)),
18716
+ get visibleTiles() {
18717
+ return this._visibleTiles;
18718
+ }
18719
+ get visibleTilesMap() {
18720
+ return this._visibleTilesMap;
18721
+ }
18722
+ get selection() {
18723
+ return this._selection;
18724
+ }
18725
+ computeVisibleTiles(z, xyzModel, webgl, camera, pMatrix, sampleCount = 9, padding = 2) {
18726
+ this._visibleTiles = XYZRayPickingUtils_js_1.default.getVisibleTilesFromViewport(z, xyzModel, webgl, camera, pMatrix, sampleCount, padding);
18727
+ this._visibleTilesMap = this.buildTileMap(this._visibleTiles);
18728
+ this.refreshAncestorsMap(this._visibleTiles);
18729
+ this._selection = {
18730
+ key: this.buildSelectionKey(z, this._visibleTiles),
18731
+ currentZoom: z,
18732
+ visibleTiles: this._visibleTiles,
18733
+ visibleTilesMap: this._visibleTilesMap,
18734
+ ancestorsMap: this._ancestorsMap,
18155
18735
  };
18156
- }
18157
- normalizePhi(phi) {
18158
- let value = phi;
18159
- while (value < 0)
18160
- value += 360;
18161
- while (value >= 360)
18162
- value -= 360;
18163
- return value;
18164
- }
18165
- buildFallbackMap(currentTiles, currentZoom) {
18166
- const fallbackMap = new Map();
18167
- const minFallbackZoom = Math.max(this._provider.minZoom, currentZoom - 2);
18168
- for (let z = currentZoom - 1; z >= minFallbackZoom; z--) {
18169
- const dz = currentZoom - z;
18170
- for (const tile of currentTiles) {
18171
- const fallback = {
18736
+ return this._selection;
18737
+ }
18738
+ refreshAncestorsMap(visibleTiles) {
18739
+ this._ancestorsMap.clear();
18740
+ for (const tile of visibleTiles) {
18741
+ for (let z = tile.z - 1; z >= 0; z--) {
18742
+ const dz = tile.z - z;
18743
+ const ancestor = {
18172
18744
  z,
18173
18745
  x: tile.x >> dz,
18174
18746
  y: tile.y >> dz,
18175
18747
  };
18176
- fallbackMap.set(`${fallback.z}/${fallback.x}/${fallback.y}`, fallback);
18748
+ this._ancestorsMap.set(`${ancestor.z}/${ancestor.x}/${ancestor.y}`, ancestor);
18177
18749
  }
18178
18750
  }
18179
- return fallbackMap;
18180
- }
18181
- buildFallbackSeedTiles(coreTiles, zoom, centerSphericalDeg) {
18182
- if (coreTiles.length === 0) {
18183
- return [];
18184
- }
18185
- const centerTile = this.getCenterTileCoord(zoom, centerSphericalDeg);
18186
- if (!centerTile) {
18187
- return coreTiles;
18188
- }
18189
- const centerKey = this.key(centerTile);
18190
- if (coreTiles.some((tile) => this.key(tile) === centerKey)) {
18191
- return coreTiles;
18192
- }
18193
- return [...coreTiles, centerTile];
18194
18751
  }
18195
- orderTilesByScreenRelevance(tiles, zoom, centerSphericalDeg) {
18196
- const centerTile = this.getCenterTileCoord(zoom, centerSphericalDeg);
18197
- if (!centerTile) {
18198
- return tiles;
18752
+ buildTileMap(tiles) {
18753
+ const map = new Map();
18754
+ for (const tile of tiles) {
18755
+ map.set(this.key(tile), tile);
18199
18756
  }
18200
- return [...tiles].sort((a, b) => {
18201
- const distanceA = Math.abs(a.x - centerTile.x) + Math.abs(a.y - centerTile.y);
18202
- const distanceB = Math.abs(b.x - centerTile.x) + Math.abs(b.y - centerTile.y);
18203
- return distanceA - distanceB;
18204
- });
18205
- }
18206
- orderFallbackTiles(tiles, currentZoom, centerSphericalDeg) {
18207
- return [...tiles].sort((a, b) => {
18208
- if (b.z !== a.z) {
18209
- return b.z - a.z;
18210
- }
18211
- const centerTileA = this.getCenterTileCoord(a.z, centerSphericalDeg);
18212
- const centerTileB = this.getCenterTileCoord(b.z, centerSphericalDeg);
18213
- if (!centerTileA || !centerTileB) {
18214
- return 0;
18215
- }
18216
- const distanceA = Math.abs(a.x - centerTileA.x) + Math.abs(a.y - centerTileA.y);
18217
- const distanceB = Math.abs(b.x - centerTileB.x) + Math.abs(b.y - centerTileB.y);
18218
- return distanceA - distanceB || currentZoom - a.z - (currentZoom - b.z);
18219
- });
18757
+ return map;
18220
18758
  }
18221
- getCenterTileCoord(zoom, centerSphericalDeg) {
18222
- if (!centerSphericalDeg) {
18223
- return null;
18224
- }
18225
- const lonDeg = centerSphericalDeg.phi > 180 ? centerSphericalDeg.phi - 360 : centerSphericalDeg.phi;
18226
- const latDeg = 90 - centerSphericalDeg.theta;
18227
- const dim = 2 ** zoom;
18228
- const x = Math.floor(((lonDeg + 180) / 360) * dim);
18229
- const latRad = (Math.max(-85.0511287798066, Math.min(85.0511287798066, latDeg)) * Math.PI) / 180;
18230
- const y = Math.floor(((1 - Math.asinh(Math.tan(latRad)) / Math.PI) / 2) * dim);
18231
- return {
18232
- z: zoom,
18233
- x: ((x % dim) + dim) % dim,
18234
- y: Math.max(0, Math.min(dim - 1, y)),
18235
- };
18759
+ buildSelectionKey(z, tiles) {
18760
+ return `${z}:${tiles.map((tile) => `${tile.x}/${tile.y}`).join('|')}`;
18236
18761
  }
18237
18762
  key(tile) {
18238
18763
  return `${tile.z}/${tile.x}/${tile.y}`;
@@ -18247,6 +18772,18 @@ exports.XYZVisibleTilesManager = XYZVisibleTilesManager;
18247
18772
  /***/ ((__unused_webpack_module, exports) => {
18248
18773
 
18249
18774
 
18775
+ /*
18776
+ * AstroViewer
18777
+ * Copyright (C) Fabrizio Giordano
18778
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
18779
+ *
18780
+ * This file is part of AstroViewer.
18781
+ * AstroViewer is distributed under a dual-license model.
18782
+ * Commercial use requires a separate commercial license.
18783
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
18784
+ *
18785
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
18786
+ */
18250
18787
  Object.defineProperty(exports, "__esModule", ({ value: true }));
18251
18788
  class Point2D {
18252
18789
  _x;
@@ -18271,6 +18808,18 @@ exports["default"] = Point2D;
18271
18808
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
18272
18809
 
18273
18810
 
18811
+ /*
18812
+ * AstroViewer
18813
+ * Copyright (C) Fabrizio Giordano
18814
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
18815
+ *
18816
+ * This file is part of AstroViewer.
18817
+ * AstroViewer is distributed under a dual-license model.
18818
+ * Commercial use requires a separate commercial license.
18819
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
18820
+ *
18821
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
18822
+ */
18274
18823
  var __importDefault = (this && this.__importDefault) || function (mod) {
18275
18824
  return (mod && mod.__esModule) ? mod : { "default": mod };
18276
18825
  };
@@ -18321,10 +18870,19 @@ class Camera {
18321
18870
  }
18322
18871
  goToPhiTheta(ptDeg) {
18323
18872
  const xyz = (0, Utils_js_1.sphericalToCartesian)(ptDeg.phi, ptDeg.theta, this.cam_pos[2]);
18873
+ const targetDirection = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), gl_matrix_1.vec3.fromValues(xyz[0], xyz[1], xyz[2]));
18874
+ const celestialNorth = gl_matrix_1.vec3.fromValues(0.0, 0.0, 1.0);
18875
+ const northProjection = gl_matrix_1.vec3.scale(gl_matrix_1.vec3.create(), targetDirection, gl_matrix_1.vec3.dot(celestialNorth, targetDirection));
18876
+ const cameraUp = gl_matrix_1.vec3.subtract(gl_matrix_1.vec3.create(), celestialNorth, northProjection);
18877
+ if (gl_matrix_1.vec3.length(cameraUp) < 1e-6) {
18878
+ gl_matrix_1.vec3.set(cameraUp, 0.0, 1.0, 0.0);
18879
+ }
18880
+ else {
18881
+ gl_matrix_1.vec3.normalize(cameraUp, cameraUp);
18882
+ }
18324
18883
  let cameraMatrix = gl_matrix_1.mat4.create();
18325
18884
  cameraMatrix = gl_matrix_1.mat4.translate(cameraMatrix, cameraMatrix, gl_matrix_1.vec3.fromValues(xyz[0], xyz[1], xyz[2]));
18326
18885
  const focusPoint = [0.0, 0.0, 0.0];
18327
- const cameraUp = gl_matrix_1.vec3.clone([0.0, 1.0, 0.0]);
18328
18886
  const cameraPos = [cameraMatrix[12], cameraMatrix[13], cameraMatrix[14]];
18329
18887
  cameraMatrix = gl_matrix_1.mat4.targetTo(cameraMatrix, cameraPos, focusPoint, cameraUp);
18330
18888
  this.R = gl_matrix_1.mat4.clone(cameraMatrix);
@@ -18477,10 +19035,6 @@ class Camera {
18477
19035
  const totRot = Math.sqrt(phi * phi + theta * theta);
18478
19036
  if (totRot === 0)
18479
19037
  return;
18480
- // If both X and Y rotations are locked, nothing to do
18481
- if (this.lockRotX && this.lockRotY) {
18482
- return;
18483
- }
18484
19038
  const pos = this.getCameraPosition();
18485
19039
  const dist2Center = Math.sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]);
18486
19040
  const distanceFromSurface = Math.max(dist2Center - 1, 1e-6);
@@ -18491,9 +19045,8 @@ class Camera {
18491
19045
  const normalizedFoV = Math.min(1, this.FoV / 18);
18492
19046
  const fovFactor = 0.06 + 1.55 * Math.pow(normalizedFoV, 0.52);
18493
19047
  const usedRot = ((totRot * distanceFactor * fovFactor) / 1.9) * this.rotationSensitivity;
18494
- // Build an axis from phi/theta, but zero components that are locked
18495
- let axisX = this.lockRotX ? 0 : theta;
18496
- let axisY = this.lockRotY ? 0 : phi;
19048
+ let axisX = theta;
19049
+ let axisY = phi;
18497
19050
  const axisLen = Math.sqrt(axisX * axisX + axisY * axisY);
18498
19051
  // If after locking we have no axis left, do nothing
18499
19052
  if (axisLen === 0) {
@@ -18614,6 +19167,18 @@ exports["default"] = Camera;
18614
19167
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
18615
19168
 
18616
19169
 
19170
+ /*
19171
+ * AstroViewer
19172
+ * Copyright (C) Fabrizio Giordano
19173
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
19174
+ *
19175
+ * This file is part of AstroViewer.
19176
+ * AstroViewer is distributed under a dual-license model.
19177
+ * Commercial use requires a separate commercial license.
19178
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
19179
+ *
19180
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
19181
+ */
18617
19182
  var __importDefault = (this && this.__importDefault) || function (mod) {
18618
19183
  return (mod && mod.__esModule) ? mod : { "default": mod };
18619
19184
  };
@@ -18884,6 +19449,18 @@ exports.HiPSShaderProgram = HiPSShaderProgram;
18884
19449
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
18885
19450
 
18886
19451
 
19452
+ /*
19453
+ * AstroViewer
19454
+ * Copyright (C) Fabrizio Giordano
19455
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
19456
+ *
19457
+ * This file is part of AstroViewer.
19458
+ * AstroViewer is distributed under a dual-license model.
19459
+ * Commercial use requires a separate commercial license.
19460
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
19461
+ *
19462
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
19463
+ */
18887
19464
  Object.defineProperty(exports, "__esModule", ({ value: true }));
18888
19465
  exports.cartesianToSpherical = cartesianToSpherical;
18889
19466
  exports.colorHex2RGB = colorHex2RGB;
@@ -18977,6 +19554,18 @@ function decDegToDMS(decDeg) {
18977
19554
  /***/ 8083:
18978
19555
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
18979
19556
 
19557
+ /*
19558
+ * AstroViewer
19559
+ * Copyright (C) Fabrizio Giordano
19560
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
19561
+ *
19562
+ * This file is part of AstroViewer.
19563
+ * AstroViewer is distributed under a dual-license model.
19564
+ * Commercial use requires a separate commercial license.
19565
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
19566
+ *
19567
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
19568
+ */
18980
19569
 
18981
19570
  var __importDefault = (this && this.__importDefault) || function (mod) {
18982
19571
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -19201,12 +19790,296 @@ class FoVUtils {
19201
19790
  exports.FoVUtils = FoVUtils;
19202
19791
 
19203
19792
 
19793
+ /***/ }),
19794
+
19795
+ /***/ 8124:
19796
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
19797
+
19798
+
19799
+ /*
19800
+ * AstroViewer
19801
+ * Copyright (C) Fabrizio Giordano
19802
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
19803
+ *
19804
+ * This file is part of AstroViewer.
19805
+ * AstroViewer is distributed under a dual-license model.
19806
+ * Commercial use requires a separate commercial license.
19807
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
19808
+ *
19809
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
19810
+ */
19811
+ var __importDefault = (this && this.__importDefault) || function (mod) {
19812
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19813
+ };
19814
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
19815
+ exports.LatLonGrid = void 0;
19816
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
19817
+ const gl_matrix_1 = __webpack_require__(1961);
19818
+ const AbstractSkyEntity_js_1 = __webpack_require__(4735);
19819
+ const XYZFoVHelper_js_1 = __webpack_require__(8284);
19820
+ const GridShaderManager_js_1 = __importDefault(__webpack_require__(4707));
19821
+ const Utils_js_1 = __webpack_require__(7930);
19822
+ const SphereFoV_js_1 = __webpack_require__(5803);
19823
+ const Global_js_1 = __importDefault(__webpack_require__(4382));
19824
+ const GridTextHelper_js_1 = __importDefault(__webpack_require__(5361));
19825
+ class LatLonGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
19826
+ static ELEM_SIZE = 3;
19827
+ static BYTES_X_ELEM = new Float32Array().BYTES_PER_ELEMENT;
19828
+ _shaderProgram;
19829
+ _vertexShader;
19830
+ _fragmentShader;
19831
+ _attribLocations = {
19832
+ position: 0,
19833
+ };
19834
+ _lonVertexPositionBuffer;
19835
+ _latVertexPositionBuffer;
19836
+ _lonStep = 10;
19837
+ _latStep = 10;
19838
+ _segmentStep = 1;
19839
+ _fovObj;
19840
+ _fovDeg = 180;
19841
+ _showGrid = true;
19842
+ _lonArray = [];
19843
+ _latArray = [];
19844
+ defaultColor = '#41d4d4';
19845
+ gridText = new GridTextHelper_js_1.default('lonlat');
19846
+ constructor(radius, position, xrad, yrad, name, webgl) {
19847
+ super(radius, position, xrad, yrad, name, webgl);
19848
+ this._fovObj = new SphereFoV_js_1.SphereFoV(webgl);
19849
+ this.init();
19850
+ }
19851
+ init() {
19852
+ this.initGL(super.webgl);
19853
+ const gl = super.webgl;
19854
+ this._shaderProgram = gl.createProgram();
19855
+ this.initShaders();
19856
+ this._lonVertexPositionBuffer = gl.createBuffer();
19857
+ this._latVertexPositionBuffer = gl.createBuffer();
19858
+ this.initBuffers(this._fovDeg);
19859
+ }
19860
+ initShaders() {
19861
+ const gl = super.webgl;
19862
+ const fsSource = GridShaderManager_js_1.default.healpixGridFS();
19863
+ this._fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
19864
+ gl.shaderSource(this._fragmentShader, fsSource);
19865
+ gl.compileShader(this._fragmentShader);
19866
+ if (!gl.getShaderParameter(this._fragmentShader, gl.COMPILE_STATUS)) {
19867
+ const log = gl.getShaderInfoLog(this._fragmentShader) || 'Unknown fragment shader error';
19868
+ console.error(log);
19869
+ alert(log);
19870
+ return;
19871
+ }
19872
+ const vsSource = GridShaderManager_js_1.default.healpixGridVS();
19873
+ this._vertexShader = gl.createShader(gl.VERTEX_SHADER);
19874
+ gl.shaderSource(this._vertexShader, vsSource);
19875
+ gl.compileShader(this._vertexShader);
19876
+ if (!gl.getShaderParameter(this._vertexShader, gl.COMPILE_STATUS)) {
19877
+ const log = gl.getShaderInfoLog(this._vertexShader) || 'Unknown vertex shader error';
19878
+ console.error(log);
19879
+ alert(log);
19880
+ return;
19881
+ }
19882
+ gl.attachShader(this._shaderProgram, this._vertexShader);
19883
+ gl.attachShader(this._shaderProgram, this._fragmentShader);
19884
+ gl.linkProgram(this._shaderProgram);
19885
+ if (!gl.getProgramParameter(this._shaderProgram, gl.LINK_STATUS)) {
19886
+ alert('Could not initialise shaders');
19887
+ }
19888
+ gl.useProgram(this._shaderProgram);
19889
+ }
19890
+ initBuffers(fovDeg) {
19891
+ const steps = XYZFoVHelper_js_1.xyzFovHelper.getLonLatSteps(fovDeg);
19892
+ this._lonStep = steps.lonStep;
19893
+ this._latStep = steps.latStep;
19894
+ this._segmentStep = Math.max(Math.min(this._lonStep, this._latStep), 0.25);
19895
+ this._lonArray = [];
19896
+ this._latArray = [];
19897
+ for (let lon = -180; lon < 180; lon += this._lonStep) {
19898
+ const vertices = [];
19899
+ for (let lat = -90; lat <= 90; lat += this._segmentStep) {
19900
+ vertices.push(...this.lonLatToCartesian(lon, Math.min(lat, 90)));
19901
+ }
19902
+ this._lonArray.push(new Float32Array(vertices));
19903
+ }
19904
+ for (let lat = -90 + this._latStep; lat < 90; lat += this._latStep) {
19905
+ const vertices = [];
19906
+ for (let lon = -180; lon <= 180; lon += this._segmentStep) {
19907
+ vertices.push(...this.lonLatToCartesian(Math.min(lon, 180), lat));
19908
+ }
19909
+ this._latArray.push(new Float32Array(vertices));
19910
+ }
19911
+ }
19912
+ lonLatToCartesian(lonDeg, latDeg) {
19913
+ const lonRad = (0, Utils_js_1.degToRad)(lonDeg);
19914
+ const latRad = (0, Utils_js_1.degToRad)(latDeg);
19915
+ const cosLat = Math.cos(latRad);
19916
+ return [
19917
+ cosLat * Math.cos(lonRad),
19918
+ cosLat * Math.sin(lonRad),
19919
+ Math.sin(latRad),
19920
+ ];
19921
+ }
19922
+ refresh(fovDeg) {
19923
+ if (Math.abs(this._fovDeg - fovDeg) > 1e-6) {
19924
+ this._fovDeg = fovDeg;
19925
+ this.initBuffers(this._fovDeg);
19926
+ }
19927
+ }
19928
+ refreshFoV(input) {
19929
+ if (!input.camera || !input.pMatrix)
19930
+ return this._fovDeg;
19931
+ this._fovObj.getFoV(Global_js_1.default.insideSphere, this, input.camera, input.pMatrix);
19932
+ this.refresh(this._fovObj.minFoV);
19933
+ return this._fovObj.minFoV;
19934
+ }
19935
+ getMinFoVDeg() {
19936
+ return this._fovObj.minFoV;
19937
+ }
19938
+ getFoV() {
19939
+ return this._fovObj;
19940
+ }
19941
+ isVisible() {
19942
+ return this._showGrid;
19943
+ }
19944
+ toggleShowGrid() {
19945
+ this._showGrid = !this._showGrid;
19946
+ return this._showGrid;
19947
+ }
19948
+ setShowGrid(showGrid) {
19949
+ this._showGrid = showGrid;
19950
+ }
19951
+ enableShader(mMatrix, pMatrix, vMatrix) {
19952
+ const gl = super.webgl;
19953
+ gl.useProgram(this._shaderProgram);
19954
+ const mvMatrix = gl_matrix_1.mat4.create();
19955
+ gl_matrix_1.mat4.multiply(mvMatrix, vMatrix, mMatrix);
19956
+ const uMVMatrixLoc = gl.getUniformLocation(this._shaderProgram, 'uMVMatrix');
19957
+ const uPMatrixLoc = gl.getUniformLocation(this._shaderProgram, 'uPMatrix');
19958
+ const uColor = gl.getUniformLocation(this._shaderProgram, 'u_fragcolor');
19959
+ this._attribLocations.position = gl.getAttribLocation(this._shaderProgram, 'aCatPosition');
19960
+ if (uMVMatrixLoc)
19961
+ gl.uniformMatrix4fv(uMVMatrixLoc, false, mvMatrix);
19962
+ if (uPMatrixLoc)
19963
+ gl.uniformMatrix4fv(uPMatrixLoc, false, pMatrix);
19964
+ if (uColor) {
19965
+ const rgb = (0, Utils_js_1.colorHex2RGB)(this.defaultColor);
19966
+ gl.uniform4f(uColor, rgb[0], rgb[1], rgb[2], 1.0);
19967
+ }
19968
+ }
19969
+ draw(input) {
19970
+ if (!this._showGrid) {
19971
+ this.gridText.resetDivSets();
19972
+ return;
19973
+ }
19974
+ const gl = super.webgl;
19975
+ const camera = input.camera;
19976
+ if (!camera)
19977
+ return;
19978
+ const pMatrix = input.pMatrix;
19979
+ if (!pMatrix)
19980
+ return;
19981
+ this.refreshFoV(input);
19982
+ const vMatrix = camera.getCameraMatrix();
19983
+ if (!vMatrix)
19984
+ return;
19985
+ const mMatrix = this.getModelMatrix();
19986
+ this.enableShader(mMatrix, pMatrix, vMatrix);
19987
+ for (const lonLine of this._lonArray) {
19988
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._lonVertexPositionBuffer);
19989
+ gl.bufferData(gl.ARRAY_BUFFER, lonLine, gl.STATIC_DRAW);
19990
+ gl.vertexAttribPointer(this._attribLocations.position, LatLonGrid.ELEM_SIZE, gl.FLOAT, false, 0, 0);
19991
+ gl.enableVertexAttribArray(this._attribLocations.position);
19992
+ gl.drawArrays(gl.LINE_STRIP, 0, lonLine.length / LatLonGrid.ELEM_SIZE);
19993
+ }
19994
+ for (const latLine of this._latArray) {
19995
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._latVertexPositionBuffer);
19996
+ gl.bufferData(gl.ARRAY_BUFFER, latLine, gl.STATIC_DRAW);
19997
+ gl.vertexAttribPointer(this._attribLocations.position, LatLonGrid.ELEM_SIZE, gl.FLOAT, false, 0, 0);
19998
+ gl.enableVertexAttribArray(this._attribLocations.position);
19999
+ gl.drawArrays(gl.LINE_LOOP, 0, latLine.length / LatLonGrid.ELEM_SIZE);
20000
+ }
20001
+ this.drawLabels(input, mMatrix, pMatrix, vMatrix);
20002
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
20003
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
20004
+ }
20005
+ drawLabels(input, mMatrix, pMatrix, vMatrix) {
20006
+ const center = input.centerSphericalDeg;
20007
+ if (!center) {
20008
+ this.gridText.resetDivSets();
20009
+ return;
20010
+ }
20011
+ const centerLon = this.normalizeLon(center.phi > 180 ? center.phi - 360 : center.phi);
20012
+ const centerLat = 90 - center.theta;
20013
+ const lonLine = this.normalizeLon(this.roundToStep(centerLon, this._lonStep));
20014
+ const latLine = Math.max(-90 + this._latStep, Math.min(90 - this._latStep, this.roundToStep(centerLat, this._latStep)));
20015
+ const lonLabelPoint = this.lonLatToCartesian(lonLine, Math.max(-80, Math.min(80, centerLat)));
20016
+ const latLabelPoint = this.lonLatToCartesian(centerLon, latLine);
20017
+ const lonScreen = this.projectPointToScreen(lonLabelPoint, mMatrix, pMatrix, vMatrix);
20018
+ if (lonScreen) {
20019
+ this.gridText.addLonLatDivSet(`${lonLine.toFixed(0)}° lon`, lonScreen.x, lonScreen.y, 'lon');
20020
+ }
20021
+ const latScreen = this.projectPointToScreen(latLabelPoint, mMatrix, pMatrix, vMatrix);
20022
+ if (latScreen) {
20023
+ this.gridText.addLonLatDivSet(`${latLine.toFixed(0)}° lat`, latScreen.x, latScreen.y, 'lat');
20024
+ }
20025
+ this.gridText.resetDivSets();
20026
+ }
20027
+ projectPointToScreen(point, mMatrix, pMatrix, vMatrix) {
20028
+ const mvMatrix = gl_matrix_1.mat4.create();
20029
+ const mvpMatrix = gl_matrix_1.mat4.create();
20030
+ gl_matrix_1.mat4.multiply(mvMatrix, vMatrix, mMatrix);
20031
+ gl_matrix_1.mat4.multiply(mvpMatrix, pMatrix, mvMatrix);
20032
+ const clipspace = gl_matrix_1.vec4.fromValues(point[0], point[1], point[2], 1);
20033
+ gl_matrix_1.vec4.transformMat4(clipspace, clipspace, mvpMatrix);
20034
+ if (Math.abs(clipspace[3]) < 1e-6) {
20035
+ return null;
20036
+ }
20037
+ clipspace[0] /= clipspace[3];
20038
+ clipspace[1] /= clipspace[3];
20039
+ if (clipspace[0] < -1 || clipspace[0] > 1 || clipspace[1] < -1 || clipspace[1] > 1) {
20040
+ return null;
20041
+ }
20042
+ const canvasRect = super.webgl.canvas.getBoundingClientRect();
20043
+ return {
20044
+ x: canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width,
20045
+ y: canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height,
20046
+ };
20047
+ }
20048
+ roundToStep(value, step) {
20049
+ if (step <= 0)
20050
+ return value;
20051
+ return Math.round(value / step) * step;
20052
+ }
20053
+ normalizeLon(lonDeg) {
20054
+ let lon = lonDeg;
20055
+ while (lon < -180)
20056
+ lon += 360;
20057
+ while (lon > 180)
20058
+ lon -= 360;
20059
+ return lon;
20060
+ }
20061
+ }
20062
+ exports.LatLonGrid = LatLonGrid;
20063
+
20064
+
19204
20065
  /***/ }),
19205
20066
 
19206
20067
  /***/ 8145:
19207
20068
  /***/ ((__unused_webpack_module, exports) => {
19208
20069
 
19209
20070
 
20071
+ /*
20072
+ * AstroViewer
20073
+ * Copyright (C) Fabrizio Giordano
20074
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20075
+ *
20076
+ * This file is part of AstroViewer.
20077
+ * AstroViewer is distributed under a dual-license model.
20078
+ * Commercial use requires a separate commercial license.
20079
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20080
+ *
20081
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20082
+ */
19210
20083
  Object.defineProperty(exports, "__esModule", ({ value: true }));
19211
20084
  exports.CoordsType = void 0;
19212
20085
  /**
@@ -19228,6 +20101,18 @@ var CoordsType;
19228
20101
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
19229
20102
 
19230
20103
 
20104
+ /*
20105
+ * AstroViewer
20106
+ * Copyright (C) Fabrizio Giordano
20107
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20108
+ *
20109
+ * This file is part of AstroViewer.
20110
+ * AstroViewer is distributed under a dual-license model.
20111
+ * Commercial use requires a separate commercial license.
20112
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20113
+ *
20114
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20115
+ */
19231
20116
  var __importDefault = (this && this.__importDefault) || function (mod) {
19232
20117
  return (mod && mod.__esModule) ? mod : { "default": mod };
19233
20118
  };
@@ -19589,12 +20474,134 @@ class Tile {
19589
20474
  exports["default"] = Tile;
19590
20475
 
19591
20476
 
20477
+ /***/ }),
20478
+
20479
+ /***/ 8284:
20480
+ /***/ ((__unused_webpack_module, exports) => {
20481
+
20482
+ /*
20483
+ * AstroViewer
20484
+ * Copyright (C) Fabrizio Giordano
20485
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20486
+ *
20487
+ * This file is part of AstroViewer.
20488
+ * AstroViewer is distributed under a dual-license model.
20489
+ * Commercial use requires a separate commercial license.
20490
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20491
+ *
20492
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20493
+ */
20494
+ // FoVHelper.ts
20495
+
20496
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
20497
+ exports.xyzFovHelper = void 0;
20498
+ class XYZFoVHelper {
20499
+ getZoom(fov) {
20500
+ if (fov >= 179)
20501
+ return 2;
20502
+ if (fov >= 90)
20503
+ return 3;
20504
+ if (fov >= 30)
20505
+ return 4;
20506
+ if (fov >= 20)
20507
+ return 5;
20508
+ if (fov >= 6)
20509
+ return 6;
20510
+ if (fov >= 3.2)
20511
+ return 7;
20512
+ if (fov >= 1.6)
20513
+ return 8;
20514
+ if (fov >= 0.85)
20515
+ return 9;
20516
+ if (fov >= 0.42)
20517
+ return 10;
20518
+ if (fov >= 0.21)
20519
+ return 11;
20520
+ if (fov >= 0.12)
20521
+ return 12;
20522
+ if (fov >= 0.06)
20523
+ return 13;
20524
+ if (fov >= 0.015)
20525
+ return 14;
20526
+ return 15;
20527
+ }
20528
+ // used in grid drawing
20529
+ getLonLatSteps(fov) {
20530
+ let lonStep;
20531
+ let latStep;
20532
+ if (fov >= 179) {
20533
+ lonStep = 10;
20534
+ latStep = 10;
20535
+ }
20536
+ else if (fov >= 25) {
20537
+ lonStep = 9;
20538
+ latStep = 9;
20539
+ }
20540
+ else if (fov >= 12.5) {
20541
+ lonStep = 8;
20542
+ latStep = 8;
20543
+ }
20544
+ else if (fov >= 6) {
20545
+ lonStep = 6;
20546
+ latStep = 6;
20547
+ }
20548
+ else if (fov >= 3.2) {
20549
+ lonStep = 5;
20550
+ latStep = 5;
20551
+ }
20552
+ else if (fov >= 1.6) {
20553
+ lonStep = 4;
20554
+ latStep = 4;
20555
+ }
20556
+ else if (fov >= 0.85) {
20557
+ lonStep = 3;
20558
+ latStep = 3;
20559
+ }
20560
+ else if (fov >= 0.42) {
20561
+ lonStep = 2;
20562
+ latStep = 2;
20563
+ }
20564
+ else if (fov >= 0.21) {
20565
+ lonStep = 1;
20566
+ latStep = 1;
20567
+ }
20568
+ else if (fov >= 0.12) {
20569
+ lonStep = 0.5;
20570
+ latStep = 0.5;
20571
+ }
20572
+ else if (fov >= 0.06) {
20573
+ lonStep = 0.25;
20574
+ latStep = 0.25;
20575
+ }
20576
+ else {
20577
+ lonStep = 10;
20578
+ latStep = 10;
20579
+ }
20580
+ return { lonStep, latStep };
20581
+ }
20582
+ }
20583
+ exports.xyzFovHelper = new XYZFoVHelper();
20584
+ exports["default"] = XYZFoVHelper;
20585
+
20586
+
19592
20587
  /***/ }),
19593
20588
 
19594
20589
  /***/ 8819:
19595
20590
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
19596
20591
 
19597
20592
 
20593
+ /*
20594
+ * AstroViewer
20595
+ * Copyright (C) Fabrizio Giordano
20596
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20597
+ *
20598
+ * This file is part of AstroViewer.
20599
+ * AstroViewer is distributed under a dual-license model.
20600
+ * Commercial use requires a separate commercial license.
20601
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20602
+ *
20603
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20604
+ */
19598
20605
  Object.defineProperty(exports, "__esModule", ({ value: true }));
19599
20606
  exports.XYZMeshBuilder = void 0;
19600
20607
  const Utils_js_1 = __webpack_require__(7930);
@@ -19634,8 +20641,7 @@ class XYZMeshBuilder {
19634
20641
  uvs[uv++] = 1 - v;
19635
20642
  }
19636
20643
  }
19637
- const triangleCount = segments * segments * 2;
19638
- const rawIndices = new Uint32Array(triangleCount * 3);
20644
+ const rawIndices = new Uint32Array(segments * segments * 2 * 3);
19639
20645
  let i = 0;
19640
20646
  for (let row = 0; row < segments; row++) {
19641
20647
  for (let col = 0; col < segments; col++) {
@@ -19697,12 +20703,112 @@ class XYZMeshBuilder {
19697
20703
  exports.XYZMeshBuilder = XYZMeshBuilder;
19698
20704
 
19699
20705
 
20706
+ /***/ }),
20707
+
20708
+ /***/ 8868:
20709
+ /***/ ((__unused_webpack_module, exports) => {
20710
+
20711
+
20712
+ /*
20713
+ * AstroViewer
20714
+ * Copyright (C) Fabrizio Giordano
20715
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20716
+ *
20717
+ * This file is part of AstroViewer.
20718
+ * AstroViewer is distributed under a dual-license model.
20719
+ * Commercial use requires a separate commercial license.
20720
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20721
+ *
20722
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20723
+ */
20724
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
20725
+ exports.XYZMapDescriptor = void 0;
20726
+ class XYZMapDescriptor {
20727
+ _name;
20728
+ _url;
20729
+ _urlResolver;
20730
+ _minZoom;
20731
+ _maxZoom;
20732
+ _segmentsPerSide;
20733
+ _tileSize;
20734
+ _maxCachedTiles;
20735
+ _interactionDebounceMs;
20736
+ _subdomains;
20737
+ _attribution;
20738
+ _flipY;
20739
+ _maxConcurrentLoads;
20740
+ constructor(name, url, minZoom = 0, maxZoom = 8, segmentsPerSide = 16, maxCachedTiles = 384, maxConcurrentLoads = 8, urlResolver) {
20741
+ this._name = name;
20742
+ this._url = url;
20743
+ this._urlResolver = urlResolver;
20744
+ this._minZoom = minZoom;
20745
+ this._maxZoom = maxZoom;
20746
+ this._segmentsPerSide = segmentsPerSide;
20747
+ this._maxCachedTiles = maxCachedTiles;
20748
+ this._interactionDebounceMs = 100;
20749
+ this._subdomains = ['a', 'b', 'c'];
20750
+ this._attribution = '';
20751
+ this._flipY = false;
20752
+ this._maxConcurrentLoads = maxConcurrentLoads;
20753
+ }
20754
+ get url() {
20755
+ return this._url;
20756
+ }
20757
+ get urlResolver() {
20758
+ return this._urlResolver;
20759
+ }
20760
+ get name() {
20761
+ return this._name;
20762
+ }
20763
+ get minZoom() {
20764
+ return this._minZoom;
20765
+ }
20766
+ get maxZoom() {
20767
+ return this._maxZoom;
20768
+ }
20769
+ get segmentsPerSide() {
20770
+ return this._segmentsPerSide;
20771
+ }
20772
+ get maxCachedTiles() {
20773
+ return this._maxCachedTiles;
20774
+ }
20775
+ get interactionDebounceMs() {
20776
+ return this._interactionDebounceMs;
20777
+ }
20778
+ get subdomains() {
20779
+ return this._subdomains;
20780
+ }
20781
+ get attribution() {
20782
+ return this._attribution;
20783
+ }
20784
+ get flipY() {
20785
+ return this._flipY;
20786
+ }
20787
+ get maxConcurrentLoads() {
20788
+ return this._maxConcurrentLoads;
20789
+ }
20790
+ }
20791
+ exports.XYZMapDescriptor = XYZMapDescriptor;
20792
+
20793
+
19700
20794
  /***/ }),
19701
20795
 
19702
20796
  /***/ 8909:
19703
20797
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
19704
20798
 
19705
20799
 
20800
+ /*
20801
+ * AstroViewer
20802
+ * Copyright (C) Fabrizio Giordano
20803
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20804
+ *
20805
+ * This file is part of AstroViewer.
20806
+ * AstroViewer is distributed under a dual-license model.
20807
+ * Commercial use requires a separate commercial license.
20808
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20809
+ *
20810
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20811
+ */
19706
20812
  var __importDefault = (this && this.__importDefault) || function (mod) {
19707
20813
  return (mod && mod.__esModule) ? mod : { "default": mod };
19708
20814
  };
@@ -19802,6 +20908,18 @@ exports.FootprintShaderProgram = FootprintShaderProgram;
19802
20908
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
19803
20909
 
19804
20910
 
20911
+ /*
20912
+ * AstroViewer
20913
+ * Copyright (C) Fabrizio Giordano
20914
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20915
+ *
20916
+ * This file is part of AstroViewer.
20917
+ * AstroViewer is distributed under a dual-license model.
20918
+ * Commercial use requires a separate commercial license.
20919
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20920
+ *
20921
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20922
+ */
19805
20923
  Object.defineProperty(exports, "__esModule", ({ value: true }));
19806
20924
  exports.TerraFootprintSetGL = void 0;
19807
20925
  const FootprintSetGL_js_1 = __webpack_require__(592);
@@ -19817,6 +20935,18 @@ exports.TerraFootprintSetGL = TerraFootprintSetGL;
19817
20935
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
19818
20936
 
19819
20937
 
20938
+ /*
20939
+ * AstroViewer
20940
+ * Copyright (C) Fabrizio Giordano
20941
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
20942
+ *
20943
+ * This file is part of AstroViewer.
20944
+ * AstroViewer is distributed under a dual-license model.
20945
+ * Commercial use requires a separate commercial license.
20946
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
20947
+ *
20948
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
20949
+ */
19820
20950
  var __importDefault = (this && this.__importDefault) || function (mod) {
19821
20951
  return (mod && mod.__esModule) ? mod : { "default": mod };
19822
20952
  };
@@ -19924,6 +21054,18 @@ exports["default"] = STCSParser;
19924
21054
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
19925
21055
 
19926
21056
 
21057
+ /*
21058
+ * AstroViewer
21059
+ * Copyright (C) Fabrizio Giordano
21060
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
21061
+ *
21062
+ * This file is part of AstroViewer.
21063
+ * AstroViewer is distributed under a dual-license model.
21064
+ * Commercial use requires a separate commercial license.
21065
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
21066
+ *
21067
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
21068
+ */
19927
21069
  Object.defineProperty(exports, "__esModule", ({ value: true }));
19928
21070
  exports.PerspectiveMatrixManager = void 0;
19929
21071
  const gl_matrix_1 = __webpack_require__(1961);
@@ -19971,6 +21113,18 @@ exports.PerspectiveMatrixManager = PerspectiveMatrixManager;
19971
21113
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
19972
21114
 
19973
21115
 
21116
+ /*
21117
+ * AstroViewer
21118
+ * Copyright (C) Fabrizio Giordano
21119
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
21120
+ *
21121
+ * This file is part of AstroViewer.
21122
+ * AstroViewer is distributed under a dual-license model.
21123
+ * Commercial use requires a separate commercial license.
21124
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
21125
+ *
21126
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
21127
+ */
19974
21128
  var __importDefault = (this && this.__importDefault) || function (mod) {
19975
21129
  return (mod && mod.__esModule) ? mod : { "default": mod };
19976
21130
  };
@@ -19997,7 +21151,7 @@ class EquatorialGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
19997
21151
  _vertexShader;
19998
21152
  _fragmentShader;
19999
21153
  defaultColor = '#41d421';
20000
- gridText = new GridTextHelper_js_1.default();
21154
+ gridText = new GridTextHelper_js_1.default('equatorial');
20001
21155
  _attribLocations = {
20002
21156
  position: 0,
20003
21157
  selected: 1,
@@ -20238,9 +21392,10 @@ class EquatorialGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
20238
21392
  // perspective divide
20239
21393
  clipspace[0] /= clipspace[3];
20240
21394
  clipspace[1] /= clipspace[3];
20241
- // clip->pixel
20242
- const pixelX = (clipspace[0] * 0.5 + 0.5) * super.webgl.canvas.width;
20243
- const pixelY = (clipspace[1] * -0.5 + 0.5) * super.webgl.canvas.height;
21395
+ // clip -> CSS pixels
21396
+ const canvasRect = super.webgl.canvas.getBoundingClientRect();
21397
+ const pixelX = canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width;
21398
+ const pixelY = canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height;
20244
21399
  this.gridText.addEqDivSet(decDeg.toFixed(2), pixelX, pixelY, 'dec');
20245
21400
  // gridTextHelper.addEqDivSet(decDeg.toFixed(2), pixelX, pixelY, 'dec');
20246
21401
  }
@@ -20261,8 +21416,9 @@ class EquatorialGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
20261
21416
  gl_matrix_1.vec4.transformMat4(clipspace, phiPoint, mvpMatrix);
20262
21417
  clipspace[0] /= clipspace[3];
20263
21418
  clipspace[1] /= clipspace[3];
20264
- const pixelX = (clipspace[0] * 0.5 + 0.5) * super.webgl.canvas.width;
20265
- const pixelY = (clipspace[1] * -0.5 + 0.5) * super.webgl.canvas.height;
21419
+ const canvasRect = super.webgl.canvas.getBoundingClientRect();
21420
+ const pixelX = canvasRect.left + (clipspace[0] * 0.5 + 0.5) * canvasRect.width;
21421
+ const pixelY = canvasRect.top + (clipspace[1] * -0.5 + 0.5) * canvasRect.height;
20266
21422
  // gridTextHelper.addEqDivSet(raDeg.toFixed(2), pixelX, pixelY, 'ra');
20267
21423
  this.gridText.addEqDivSet(raDeg.toFixed(2), pixelX, pixelY, 'ra');
20268
21424
  }
@@ -20343,14 +21499,28 @@ var __webpack_exports__ = {};
20343
21499
  (() => {
20344
21500
  var exports = __webpack_exports__;
20345
21501
 
21502
+ /*
21503
+ * AstroViewer
21504
+ * Copyright (C) Fabrizio Giordano
21505
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
21506
+ *
21507
+ * This file is part of AstroViewer.
21508
+ * AstroViewer is distributed under a dual-license model.
21509
+ * Commercial use requires a separate commercial license.
21510
+ * Non-commercial use is governed by LICENSE-NONCOMMERCIAL.md.
21511
+ *
21512
+ * See LICENSE.md, LICENSE-COMMERCIAL.md, and LICENSE-NONCOMMERCIAL.md for details.
21513
+ */
20346
21514
  Object.defineProperty(exports, "__esModule", ({ value: true }));
20347
- exports.Footprint = exports.Source = exports.WMTSAdapter = exports.XYZLayer = exports.HiPS = exports.createColorMapFromSamples = exports.COLOR_MAP_SAMPLE_COUNT = exports.ColorMaps = exports.CoordsType = exports.FoVUtils = exports.CartesianOpts = exports.PointInitOpts = exports.AstroOpts = exports.SphericalOpts = exports.Point = exports.ColumnType = exports.MetadataInit = exports.MetadataColumn = exports.MetadataManager = exports.TerraFootprintSetGL = exports.TerraPointSetGL = exports.CatalogueGL = exports.FootprintSetGL = exports.HoveredFootprintDetail = exports.FoV = exports.HiPSDescriptor = exports.AstroViewer = void 0;
21515
+ exports.Footprint = exports.Source = exports.WMTSAdapter = exports.XYZMap = exports.HiPS = exports.createColorMapFromSamples = exports.COLOR_MAP_SAMPLE_COUNT = exports.ColorMaps = exports.CoordsType = exports.FoVUtils = exports.CartesianOpts = exports.PointInitOpts = exports.AstroOpts = exports.SphericalOpts = exports.Point = exports.ColumnType = exports.MetadataInit = exports.MetadataColumn = exports.MetadataManager = exports.TerraFootprintSetGL = exports.TerraPointSetGL = exports.CatalogueGL = exports.FootprintSetGL = exports.HoveredFootprintDetail = exports.SphereFoV = exports.FoV = exports.HiPSDescriptor = exports.AstroViewer = void 0;
20348
21516
  var AstroViewer_js_1 = __webpack_require__(772);
20349
21517
  Object.defineProperty(exports, "AstroViewer", ({ enumerable: true, get: function () { return AstroViewer_js_1.AstroViewer; } }));
20350
21518
  var HiPSDescriptor_js_1 = __webpack_require__(5087);
20351
21519
  Object.defineProperty(exports, "HiPSDescriptor", ({ enumerable: true, get: function () { return HiPSDescriptor_js_1.HiPSDescriptor; } }));
20352
- var FoV_js_1 = __webpack_require__(3576);
20353
- Object.defineProperty(exports, "FoV", ({ enumerable: true, get: function () { return FoV_js_1.FoV; } }));
21520
+ var SphereFoV_js_1 = __webpack_require__(5803);
21521
+ Object.defineProperty(exports, "FoV", ({ enumerable: true, get: function () { return SphereFoV_js_1.SphereFoV; } }));
21522
+ var SphereFoV_js_2 = __webpack_require__(5803);
21523
+ Object.defineProperty(exports, "SphereFoV", ({ enumerable: true, get: function () { return SphereFoV_js_2.SphereFoV; } }));
20354
21524
  var FootprintSetGL_js_1 = __webpack_require__(592);
20355
21525
  Object.defineProperty(exports, "HoveredFootprintDetail", ({ enumerable: true, get: function () { return FootprintSetGL_js_1.HoveredFootprintDetail; } }));
20356
21526
  Object.defineProperty(exports, "FootprintSetGL", ({ enumerable: true, get: function () { return FootprintSetGL_js_1.FootprintSetGL; } }));
@@ -20382,9 +21552,9 @@ Object.defineProperty(exports, "COLOR_MAP_SAMPLE_COUNT", ({ enumerable: true, ge
20382
21552
  Object.defineProperty(exports, "createColorMapFromSamples", ({ enumerable: true, get: function () { return ColorMaps_js_1.createColorMapFromSamples; } }));
20383
21553
  var HiPS_js_1 = __webpack_require__(3726);
20384
21554
  Object.defineProperty(exports, "HiPS", ({ enumerable: true, get: function () { return HiPS_js_1.HiPS; } }));
20385
- var XYZLayer_js_1 = __webpack_require__(2502);
20386
- Object.defineProperty(exports, "XYZLayer", ({ enumerable: true, get: function () { return XYZLayer_js_1.XYZLayer; } }));
20387
- var WMTSAdapter_js_1 = __webpack_require__(3768);
21555
+ var XYZMap_js_1 = __webpack_require__(1741);
21556
+ Object.defineProperty(exports, "XYZMap", ({ enumerable: true, get: function () { return XYZMap_js_1.XYZMap; } }));
21557
+ var WMTSAdapter_js_1 = __webpack_require__(3956);
20388
21558
  Object.defineProperty(exports, "WMTSAdapter", ({ enumerable: true, get: function () { return WMTSAdapter_js_1.WMTSAdapter; } }));
20389
21559
  var Source_js_1 = __webpack_require__(146);
20390
21560
  Object.defineProperty(exports, "Source", ({ enumerable: true, get: function () { return Source_js_1.Source; } }));