astro-viewer 3.11.0 → 3.12.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 (72) hide show
  1. package/dist/astroviewer.cjs +561 -149
  2. package/dist/astroviewer.cjs.map +1 -1
  3. package/dist/astroviewer.js +561 -149
  4. package/dist/astroviewer.js.map +1 -1
  5. package/dist/astroviewer.min.js +1 -1
  6. package/dist/astroviewer.min.js.map +1 -1
  7. package/lib-esm/AstroSphere.d.ts +36 -2
  8. package/lib-esm/AstroSphere.d.ts.map +1 -1
  9. package/lib-esm/AstroSphere.js +234 -70
  10. package/lib-esm/AstroSphere.js.map +1 -1
  11. package/lib-esm/AstroViewer.d.ts +14 -1
  12. package/lib-esm/AstroViewer.d.ts.map +1 -1
  13. package/lib-esm/AstroViewer.js +38 -4
  14. package/lib-esm/AstroViewer.js.map +1 -1
  15. package/lib-esm/Camera.d.ts +8 -0
  16. package/lib-esm/Camera.d.ts.map +1 -1
  17. package/lib-esm/Camera.js +16 -0
  18. package/lib-esm/Camera.js.map +1 -1
  19. package/lib-esm/index.d.ts +1 -0
  20. package/lib-esm/index.d.ts.map +1 -1
  21. package/lib-esm/index.js +1 -0
  22. package/lib-esm/index.js.map +1 -1
  23. package/lib-esm/model/Source.js +1 -1
  24. package/lib-esm/model/Source.js.map +1 -1
  25. package/lib-esm/model/catalogues/CatalogueGL.d.ts +13 -4
  26. package/lib-esm/model/catalogues/CatalogueGL.d.ts.map +1 -1
  27. package/lib-esm/model/catalogues/CatalogueGL.js +109 -59
  28. package/lib-esm/model/catalogues/CatalogueGL.js.map +1 -1
  29. package/lib-esm/model/earth/XYZMap.d.ts +4 -1
  30. package/lib-esm/model/earth/XYZMap.d.ts.map +1 -1
  31. package/lib-esm/model/earth/XYZMap.js +35 -2
  32. package/lib-esm/model/earth/XYZMap.js.map +1 -1
  33. package/lib-esm/model/footprints/FootprintSetGL.d.ts +1 -0
  34. package/lib-esm/model/footprints/FootprintSetGL.d.ts.map +1 -1
  35. package/lib-esm/model/footprints/FootprintSetGL.js +13 -3
  36. package/lib-esm/model/footprints/FootprintSetGL.js.map +1 -1
  37. package/lib-esm/model/grid/EquatorialGrid.d.ts +1 -0
  38. package/lib-esm/model/grid/EquatorialGrid.d.ts.map +1 -1
  39. package/lib-esm/model/grid/EquatorialGrid.js +3 -0
  40. package/lib-esm/model/grid/EquatorialGrid.js.map +1 -1
  41. package/lib-esm/model/grid/HealpixGrid.d.ts +1 -0
  42. package/lib-esm/model/grid/HealpixGrid.d.ts.map +1 -1
  43. package/lib-esm/model/grid/HealpixGrid.js +3 -0
  44. package/lib-esm/model/grid/HealpixGrid.js.map +1 -1
  45. package/lib-esm/model/grid/LonLatGrid.d.ts +1 -0
  46. package/lib-esm/model/grid/LonLatGrid.d.ts.map +1 -1
  47. package/lib-esm/model/grid/LonLatGrid.js +3 -0
  48. package/lib-esm/model/grid/LonLatGrid.js.map +1 -1
  49. package/lib-esm/model/meships/MeshHiPS.d.ts +4 -0
  50. package/lib-esm/model/meships/MeshHiPS.d.ts.map +1 -1
  51. package/lib-esm/model/meships/MeshHiPS.js +11 -1
  52. package/lib-esm/model/meships/MeshHiPS.js.map +1 -1
  53. package/lib-esm/model/terra/TerraPointSetGL.d.ts +1 -0
  54. package/lib-esm/model/terra/TerraPointSetGL.d.ts.map +1 -1
  55. package/lib-esm/model/terra/TerraPointSetGL.js +39 -1
  56. package/lib-esm/model/terra/TerraPointSetGL.js.map +1 -1
  57. package/lib-esm/shader/CatalogueShaderProgram.d.ts +4 -0
  58. package/lib-esm/shader/CatalogueShaderProgram.d.ts.map +1 -1
  59. package/lib-esm/shader/CatalogueShaderProgram.js +6 -0
  60. package/lib-esm/shader/CatalogueShaderProgram.js.map +1 -1
  61. package/lib-esm/shader/ShaderManager.d.ts.map +1 -1
  62. package/lib-esm/shader/ShaderManager.js +7 -4
  63. package/lib-esm/shader/ShaderManager.js.map +1 -1
  64. package/lib-esm/shader/XYZShaderProgram.d.ts +3 -0
  65. package/lib-esm/shader/XYZShaderProgram.d.ts.map +1 -1
  66. package/lib-esm/shader/XYZShaderProgram.js +11 -3
  67. package/lib-esm/shader/XYZShaderProgram.js.map +1 -1
  68. package/lib-esm/utils/Utils.d.ts +12 -0
  69. package/lib-esm/utils/Utils.d.ts.map +1 -1
  70. package/lib-esm/utils/Utils.js +26 -0
  71. package/lib-esm/utils/Utils.js.map +1 -1
  72. package/package.json +2 -2
@@ -3641,12 +3641,18 @@ class AstroSphere {
3641
3641
  _activeHiPS = null;
3642
3642
  _activeHiPSLayers = [];
3643
3643
  _activeXYZ2 = null;
3644
+ _earthRasterOverlays = [];
3645
+ _earthRasterOverlaySequence = 0;
3644
3646
  _activeMeshHiPS = null;
3645
3647
  _activeBaseLayer = null;
3648
+ _activeDomain = "astronomy";
3649
+ domainCameraStates = {};
3646
3650
  startup = true;
3647
3651
  fov;
3648
- activeCatalogues = [];
3649
- activeFootprintSets = [];
3652
+ astronomyCatalogues = [];
3653
+ earthPointSets = [];
3654
+ astronomyFootprintSets = [];
3655
+ earthFootprintSets = [];
3650
3656
  activePolylineSets = [];
3651
3657
  activeSensorCones = [];
3652
3658
  activeSatelliteObjects = [];
@@ -3879,9 +3885,7 @@ class AstroSphere {
3879
3885
  return true;
3880
3886
  }
3881
3887
  emitCameraChanged(reason) {
3882
- // avoid dispatch before scene is ready
3883
- if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
3884
- return;
3888
+ // Camera interaction remains meaningful even when no base layer is active.
3885
3889
  if (!this._healpixGrid?.fovObj)
3886
3890
  return;
3887
3891
  const detail = this.getCurrentStatus();
@@ -3946,8 +3950,11 @@ class AstroSphere {
3946
3950
  if (mousePoint && mousePoint.length > 0) {
3947
3951
  this.mouseHelper.update(mousePoint);
3948
3952
  this.updateLastMousePoint();
3949
- for (const cat of this.activeCatalogues) {
3950
- const clickResult = cat.selectPrimarySourceFromClick(this.mouseHelper);
3953
+ for (const cat of this.getActivePointSets()) {
3954
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
3955
+ if (!activeModelMatrix)
3956
+ continue;
3957
+ const clickResult = cat.selectPrimarySourceFromClick(this.mouseHelper, activeModelMatrix, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
3951
3958
  if (!clickResult?.sources.length)
3952
3959
  continue;
3953
3960
  this._webgl.canvas.dispatchEvent(new CustomEvent("source-clicked", {
@@ -3960,7 +3967,7 @@ class AstroSphere {
3960
3967
  composed: true,
3961
3968
  }));
3962
3969
  }
3963
- for (const fset of this.activeFootprintSets) {
3970
+ for (const fset of this.getActiveFootprintSets()) {
3964
3971
  const clickResult = fset.selectPrimaryFootprintFromClick(this.mouseHelper);
3965
3972
  if (!clickResult?.footprints.length)
3966
3973
  continue;
@@ -4057,8 +4064,11 @@ class AstroSphere {
4057
4064
  }
4058
4065
  this.mouseHelper.update(mousePoint);
4059
4066
  this.updateLastMousePoint();
4060
- for (const cat of this.activeCatalogues) {
4061
- const pickResult = cat.getSourcesFromPointer(this.mouseHelper);
4067
+ for (const cat of this.getActivePointSets()) {
4068
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4069
+ if (!activeModelMatrix)
4070
+ continue;
4071
+ const pickResult = cat.getSourcesFromPointer(this.mouseHelper, activeModelMatrix, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4062
4072
  if (!pickResult?.sources.length)
4063
4073
  continue;
4064
4074
  this._webgl.canvas.dispatchEvent(new CustomEvent("source-contextmenu", {
@@ -4073,7 +4083,7 @@ class AstroSphere {
4073
4083
  }));
4074
4084
  break;
4075
4085
  }
4076
- for (const fset of this.activeFootprintSets) {
4086
+ for (const fset of this.getActiveFootprintSets()) {
4077
4087
  const pickResult = fset.getFootprintsFromPointer(this.mouseHelper);
4078
4088
  if (!pickResult?.footprints.length)
4079
4089
  continue;
@@ -4163,19 +4173,22 @@ class AstroSphere {
4163
4173
  return new HiPS_js_1.HiPS(1, [0.0, 0.0, 0.0], 0, 0, hipsDescriptor, this._webgl, this._healpixGrid);
4164
4174
  }
4165
4175
  activateHiPS(hipsDescriptor) {
4176
+ if (this._activeHiPSLayers.length > 0) {
4177
+ throw new Error("Cannot load a HiPS base layer while stacked layers are active.");
4178
+ }
4166
4179
  const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
4167
- for (const hips of this._activeHiPSLayers) {
4168
- tileBuffer.removeHiPS(hips);
4180
+ if (this._activeHiPS) {
4181
+ tileBuffer.removeHiPS(this._activeHiPS);
4169
4182
  }
4170
- this._activeHiPSLayers = [];
4171
4183
  const hips = this.createHiPS(hipsDescriptor);
4172
- this._activeHiPSLayers.push(hips);
4173
4184
  this._activeHiPS = hips;
4185
+ this._activeDomain = "astronomy";
4174
4186
  this._activeBaseLayer = "hips";
4175
4187
  return hips;
4176
4188
  }
4177
4189
  setHiPSOpacity(hips, opacity) {
4178
- if (!this._activeHiPSLayers.includes(hips)) {
4190
+ const isBaseLayer = this._activeHiPSLayers.length === 0 && this._activeHiPS === hips;
4191
+ if (!isBaseLayer && !this._activeHiPSLayers.includes(hips)) {
4179
4192
  throw new Error("HiPS layer is not active in this AstroSphere.");
4180
4193
  }
4181
4194
  hips.setOpacity(opacity);
@@ -4183,6 +4196,13 @@ class AstroSphere {
4183
4196
  addHiPS(hipsDescriptor) {
4184
4197
  const normalizeURL = (url) => String(url).replace(/\/+$/, "");
4185
4198
  const descriptorURL = normalizeURL(hipsDescriptor.url);
4199
+ // Entering stack mode discards the standalone base HiPS. Base mode and
4200
+ // stack mode are intentionally mutually exclusive.
4201
+ if (this._activeHiPSLayers.length === 0 && this._activeHiPS) {
4202
+ const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
4203
+ tileBuffer.removeHiPS(this._activeHiPS);
4204
+ this._activeHiPS = null;
4205
+ }
4186
4206
  const existing = this._activeHiPSLayers.find((hips) => normalizeURL(hips.baseURL) === descriptorURL);
4187
4207
  if (existing) {
4188
4208
  throw new Error(`HiPS already active: ${String(hipsDescriptor.url)}`);
@@ -4190,6 +4210,7 @@ class AstroSphere {
4190
4210
  const hips = this.createHiPS(hipsDescriptor);
4191
4211
  this._activeHiPSLayers.push(hips);
4192
4212
  this._activeHiPS = hips;
4213
+ this._activeDomain = "astronomy";
4193
4214
  this._activeBaseLayer = "hips";
4194
4215
  return hips;
4195
4216
  }
@@ -4214,8 +4235,13 @@ class AstroSphere {
4214
4235
  }
4215
4236
  removeAllHiPS() {
4216
4237
  const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
4217
- for (const hips of this._activeHiPSLayers) {
4218
- tileBuffer.removeHiPS(hips);
4238
+ if (this._activeHiPSLayers.length === 0 && this._activeHiPS) {
4239
+ tileBuffer.removeHiPS(this._activeHiPS);
4240
+ }
4241
+ else {
4242
+ for (const hips of this._activeHiPSLayers) {
4243
+ tileBuffer.removeHiPS(hips);
4244
+ }
4219
4245
  }
4220
4246
  this._activeHiPSLayers = [];
4221
4247
  this._activeHiPS = null;
@@ -4228,39 +4254,169 @@ class AstroSphere {
4228
4254
  this._activeBaseLayer = "xyz";
4229
4255
  }
4230
4256
  activateXYZ2(config) {
4257
+ this._activeDomain = "earth";
4231
4258
  this._activeXYZ2 = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, config, this._webgl, this.gridLabelContainers);
4232
4259
  this._activeBaseLayer = "xyz";
4233
4260
  }
4234
4261
  activateMeshHiPS(descriptor) {
4262
+ this._activeDomain = "mesh";
4235
4263
  this._activeMeshHiPS = new MeshHiPS_js_1.MeshHiPS(descriptor.meshRadius, [0.0, 0.0, 0.0], 0, 0, descriptor, this._webgl, this._healpixGrid);
4236
4264
  this._activeBaseLayer = "meships";
4237
4265
  }
4266
+ setMeshHiPSColor(color) {
4267
+ this._activeMeshHiPS?.setColor(color);
4268
+ }
4269
+ setMeshHiPSWireframe(wireframe) {
4270
+ this._activeMeshHiPS?.setWireframe(wireframe);
4271
+ }
4238
4272
  activateWMTS(config) {
4273
+ this._activeDomain = "earth";
4239
4274
  const adapter = new WMTSAdapter_js_1.WMTSAdapter(config);
4240
4275
  const xyzConfig = adapter.toXYZLayerConfig();
4241
4276
  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, this.gridLabelContainers);
4242
4277
  this._activeBaseLayer = "xyz";
4243
4278
  }
4244
- // Catalogue section
4279
+ addXYZRasterOverlay(config) {
4280
+ const map = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, config, this._webgl, this.gridLabelContainers);
4281
+ return this.addEarthRasterOverlay(config.name, "xyz", map);
4282
+ }
4283
+ addWMTSRasterOverlay(config) {
4284
+ const adapter = new WMTSAdapter_js_1.WMTSAdapter(config);
4285
+ const xyzConfig = adapter.toXYZLayerConfig();
4286
+ const name = config.layer ? `WMTS ${config.layer}` : "WMTS Earth Raster Overlay";
4287
+ const map = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, new XYZMapDescriptor_js_1.XYZMapDescriptor(name, xyzConfig.urlTemplate, xyzConfig.minZoom ?? 0, xyzConfig.maxZoom ?? 8, xyzConfig.segmentsPerSide ?? 48, xyzConfig.maxCachedTiles ?? 384, 8, xyzConfig.urlResolver), this._webgl, this.gridLabelContainers);
4288
+ return this.addEarthRasterOverlay(name, "wmts", map);
4289
+ }
4290
+ getEarthRasterOverlays() {
4291
+ return this._earthRasterOverlays.map(({ map: _map, ...overlay }) => ({ ...overlay }));
4292
+ }
4293
+ setEarthRasterOverlayOpacity(id, opacity) {
4294
+ const overlay = this._earthRasterOverlays.find((entry) => entry.id === id);
4295
+ if (!overlay)
4296
+ return;
4297
+ overlay.opacity = Math.min(1, Math.max(0, opacity));
4298
+ overlay.map.setOpacity(overlay.opacity);
4299
+ }
4300
+ setEarthRasterOverlayVisible(id, visible) {
4301
+ const overlay = this._earthRasterOverlays.find((entry) => entry.id === id);
4302
+ if (overlay)
4303
+ overlay.visible = visible;
4304
+ }
4305
+ removeEarthRasterOverlay(id) {
4306
+ this._earthRasterOverlays = this._earthRasterOverlays.filter((entry) => entry.id !== id);
4307
+ }
4308
+ removeAllEarthRasterOverlays() {
4309
+ this._earthRasterOverlays = [];
4310
+ }
4311
+ addEarthRasterOverlay(name, sourceType, map) {
4312
+ const overlay = {
4313
+ id: `earth-raster-${++this._earthRasterOverlaySequence}`,
4314
+ name,
4315
+ sourceType,
4316
+ visible: true,
4317
+ opacity: 0.65,
4318
+ map,
4319
+ };
4320
+ map.setOpacity(overlay.opacity);
4321
+ this._earthRasterOverlays.push(overlay);
4322
+ const { map: _map, ...info } = overlay;
4323
+ return { ...info };
4324
+ }
4325
+ setActiveDomain(domain) {
4326
+ if (domain !== this._activeDomain) {
4327
+ this.clearGridLabelsForDomain(this._activeDomain);
4328
+ this.domainCameraStates[this._activeDomain] = this._camera.getViewState();
4329
+ const targetCameraState = this.domainCameraStates[domain];
4330
+ if (targetCameraState) {
4331
+ this._camera.restoreViewState(targetCameraState);
4332
+ }
4333
+ this.inertiaX = 0;
4334
+ this.inertiaY = 0;
4335
+ this.zoomInertia = 0;
4336
+ this._cameraStatusChanged = true;
4337
+ }
4338
+ this._activeDomain = domain;
4339
+ if (domain === "astronomy") {
4340
+ this._activeBaseLayer = this._activeHiPS ? "hips" : null;
4341
+ }
4342
+ else if (domain === "earth") {
4343
+ this._activeBaseLayer = this._activeXYZ2 ? "xyz" : null;
4344
+ }
4345
+ else {
4346
+ this._activeBaseLayer = this._activeMeshHiPS ? "meships" : null;
4347
+ }
4348
+ // A hover from the previous vertical must not leak into the new one.
4349
+ this.lastHoveredSource = null;
4350
+ this.lastHoveredCatalogue = null;
4351
+ }
4352
+ clearGridLabelsForDomain(domain) {
4353
+ if (domain === "astronomy") {
4354
+ this._healpixGrid?.clearLabels();
4355
+ this._equatorialGrid?.clearLabels();
4356
+ return;
4357
+ }
4358
+ if (domain === "earth") {
4359
+ this._activeXYZ2?.clearLonLatGridLabels?.();
4360
+ }
4361
+ }
4362
+ get activeDomain() {
4363
+ return this._activeDomain;
4364
+ }
4365
+ getActivePointSets() {
4366
+ if (this._activeDomain === "astronomy")
4367
+ return this.astronomyCatalogues;
4368
+ if (this._activeDomain === "earth")
4369
+ return this.earthPointSets;
4370
+ return [];
4371
+ }
4372
+ getActiveFootprintSets() {
4373
+ if (this._activeDomain === "astronomy")
4374
+ return this.astronomyFootprintSets;
4375
+ if (this._activeDomain === "earth")
4376
+ return this.earthFootprintSets;
4377
+ return [];
4378
+ }
4379
+ // Astronomy catalogue ownership
4245
4380
  async showCatalogue(cat) {
4246
- // console.log(cat)
4247
- if (cat)
4248
- this.activeCatalogues.push(cat);
4381
+ if (cat && !this.astronomyCatalogues.includes(cat)) {
4382
+ this.astronomyCatalogues.push(cat);
4383
+ }
4249
4384
  return cat;
4250
4385
  }
4251
4386
  deleteCatalogue(catalogue) {
4252
- this.activeCatalogues = this.activeCatalogues.filter((c) => c !== catalogue);
4387
+ this.astronomyCatalogues = this.astronomyCatalogues.filter((c) => c !== catalogue);
4253
4388
  }
4254
- // End Catalogue section
4255
- // Footprint section
4389
+ // Earth point-set ownership. TerraPointSetGL still extends CatalogueGL in
4390
+ // 3.12, but it no longer shares the Astronomy lifecycle collection.
4391
+ async showTerraPointSet(pointSet) {
4392
+ if (pointSet && !this.earthPointSets.includes(pointSet)) {
4393
+ this.earthPointSets.push(pointSet);
4394
+ }
4395
+ return pointSet;
4396
+ }
4397
+ deleteTerraPointSet(pointSet) {
4398
+ this.earthPointSets = this.earthPointSets.filter((set) => set !== pointSet);
4399
+ }
4400
+ // Astronomy footprint ownership
4256
4401
  async showFootprintSet(fset) {
4257
- // console.log(fset)
4258
- if (fset)
4259
- this.activeFootprintSets.push(fset);
4402
+ if (fset && !this.astronomyFootprintSets.includes(fset)) {
4403
+ this.astronomyFootprintSets.push(fset);
4404
+ }
4260
4405
  return fset;
4261
4406
  }
4262
4407
  deleteFootprintSet(footprintSet) {
4263
- this.activeFootprintSets = this.activeFootprintSets.filter((fst) => fst !== footprintSet);
4408
+ this.astronomyFootprintSets = this.astronomyFootprintSets.filter((fst) => fst !== footprintSet);
4409
+ }
4410
+ // Earth footprint ownership. TerraFootprintSetGL still reuses the common
4411
+ // FootprintSetGL rendering implementation, but has an independent lifecycle.
4412
+ async showTerraFootprintSet(footprintSet) {
4413
+ if (footprintSet && !this.earthFootprintSets.includes(footprintSet)) {
4414
+ this.earthFootprintSets.push(footprintSet);
4415
+ }
4416
+ return footprintSet;
4417
+ }
4418
+ deleteTerraFootprintSet(footprintSet) {
4419
+ this.earthFootprintSets = this.earthFootprintSets.filter((fst) => fst !== footprintSet);
4264
4420
  }
4265
4421
  async showPolylineSet(polylineSet) {
4266
4422
  if (polylineSet)
@@ -4290,8 +4446,8 @@ class AstroSphere {
4290
4446
  satelliteObject.dispose();
4291
4447
  }
4292
4448
  getHoveredFootprints() {
4293
- let footprintsHovered = [];
4294
- this.activeFootprintSets.forEach((fset) => {
4449
+ const footprintsHovered = [];
4450
+ this.getActiveFootprintSets().forEach((fset) => {
4295
4451
  footprintsHovered.push(fset.hoveredFootprints);
4296
4452
  });
4297
4453
  return footprintsHovered;
@@ -4523,8 +4679,6 @@ class AstroSphere {
4523
4679
  return;
4524
4680
  if (!this._webgl)
4525
4681
  return;
4526
- if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
4527
- return;
4528
4682
  if (!this._healpixGrid || Object.keys(this._healpixGrid).length === 0)
4529
4683
  return;
4530
4684
  if (this._healpixGrid.fovObj === undefined)
@@ -4636,8 +4790,10 @@ class AstroSphere {
4636
4790
  this._webgl.enable(this._webgl.CULL_FACE);
4637
4791
  this._webgl.cullFace(Global_js_1.default.insideSphere ? this._webgl.FRONT : this._webgl.BACK);
4638
4792
  this._webgl.blendFunc(this._webgl.SRC_ALPHA, this._webgl.ONE_MINUS_SRC_ALPHA);
4639
- if (this._activeBaseLayer === "hips" && this._activeHiPSLayers.length > 0) {
4640
- const maxHiPSOrder = Math.max(...this._activeHiPSLayers.map((hips) => hips.maxOrder));
4793
+ if (this._activeBaseLayer === "hips" && this._activeHiPS) {
4794
+ const maxHiPSOrder = this._activeHiPSLayers.length > 0
4795
+ ? Math.max(...this._activeHiPSLayers.map((hips) => hips.maxOrder))
4796
+ : this._activeHiPS.maxOrder;
4641
4797
  const visibleOrder = Math.min(this._healpixGrid.visibleorder, maxHiPSOrder);
4642
4798
  this._healpixGrid.visibleTilesManager.computeVisiblePixels(visibleOrder, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
4643
4799
  }
@@ -4672,12 +4828,19 @@ class AstroSphere {
4672
4828
  }
4673
4829
  if (this._activeBaseLayer === "xyz") {
4674
4830
  this._activeXYZ2?.draw(skyEntityDrawInput);
4831
+ for (const overlay of this._earthRasterOverlays) {
4832
+ if (overlay.visible) {
4833
+ overlay.map.draw(skyEntityDrawInput, true);
4834
+ }
4835
+ }
4675
4836
  }
4676
4837
  if (this._activeBaseLayer === "meships") {
4677
4838
  this._activeMeshHiPS?.draw(skyEntityDrawInput);
4678
4839
  }
4679
- this._healpixGrid.draw(skyEntityDrawInput);
4680
- this._equatorialGrid.draw(skyEntityDrawInput);
4840
+ if (this._activeDomain === "astronomy") {
4841
+ this._healpixGrid.draw(skyEntityDrawInput);
4842
+ this._equatorialGrid.draw(skyEntityDrawInput);
4843
+ }
4681
4844
  this._webgl.enable(this._webgl.DEPTH_TEST);
4682
4845
  this._webgl.disable(this._webgl.CULL_FACE);
4683
4846
  if (this.startup) {
@@ -4696,52 +4859,53 @@ class AstroSphere {
4696
4859
  decDMS,
4697
4860
  });
4698
4861
  }
4699
- this.activeCatalogues.forEach((cat) => {
4700
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4701
- this._activeXYZ2?.getModelMatrix() ??
4702
- this._activeMeshHiPS?.getModelMatrix();
4862
+ this.getActivePointSets().forEach((cat) => {
4863
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4703
4864
  if (activeModelMatrix) {
4704
4865
  cat.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4705
4866
  }
4706
4867
  });
4707
4868
  this.emitHoveredSourceIfChanged();
4708
- this.activeFootprintSets.forEach((fst) => {
4709
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4710
- this._activeXYZ2?.getModelMatrix() ??
4711
- this._activeMeshHiPS?.getModelMatrix();
4869
+ this.getActiveFootprintSets().forEach((fst) => {
4870
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4712
4871
  if (activeModelMatrix) {
4713
4872
  fst.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4714
4873
  }
4715
4874
  });
4716
- this.activePolylineSets.forEach((polylineSet) => {
4717
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4718
- this._activeXYZ2?.getModelMatrix() ??
4719
- this._activeMeshHiPS?.getModelMatrix();
4720
- if (activeModelMatrix) {
4721
- polylineSet.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4722
- }
4723
- });
4724
- this.activeSensorCones.forEach((sensorCone) => {
4725
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4726
- this._activeXYZ2?.getModelMatrix() ??
4727
- this._activeMeshHiPS?.getModelMatrix();
4728
- if (activeModelMatrix) {
4729
- sensorCone.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4730
- }
4731
- });
4732
- this.activeSatelliteObjects.forEach((satelliteObject) => {
4733
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4734
- this._activeXYZ2?.getModelMatrix() ??
4735
- this._activeMeshHiPS?.getModelMatrix();
4736
- if (activeModelMatrix) {
4737
- satelliteObject.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4738
- }
4739
- });
4875
+ if (this._activeDomain === "earth") {
4876
+ this.activePolylineSets.forEach((polylineSet) => {
4877
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4878
+ if (activeModelMatrix) {
4879
+ polylineSet.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4880
+ }
4881
+ });
4882
+ this.activeSensorCones.forEach((sensorCone) => {
4883
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4884
+ if (activeModelMatrix) {
4885
+ sensorCone.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4886
+ }
4887
+ });
4888
+ this.activeSatelliteObjects.forEach((satelliteObject) => {
4889
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4890
+ if (activeModelMatrix) {
4891
+ satelliteObject.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4892
+ }
4893
+ });
4894
+ }
4895
+ }
4896
+ getActiveDomainModelMatrix() {
4897
+ if (this._activeDomain === "astronomy") {
4898
+ return (this._activeHiPS?.getModelMatrix() ?? this._healpixGrid.getModelMatrix());
4899
+ }
4900
+ if (this._activeDomain === "earth") {
4901
+ return (this._activeXYZ2?.getModelMatrix() ?? this._healpixGrid.getModelMatrix());
4902
+ }
4903
+ return (this._activeMeshHiPS?.getModelMatrix() ?? this._healpixGrid.getModelMatrix());
4740
4904
  }
4741
4905
  emitHoveredSourceIfChanged() {
4742
4906
  let nextHoveredSource = null;
4743
4907
  let nextHoveredCatalogue = null;
4744
- for (const cat of this.activeCatalogues) {
4908
+ for (const cat of this.getActivePointSets()) {
4745
4909
  const hovered = cat.getPrimaryHoveredSource();
4746
4910
  if (!hovered)
4747
4911
  continue;
@@ -4870,25 +5034,25 @@ class AstroViewer {
4870
5034
  return new TerraPointSetGL_js_1.TerraPointSetGL(pointSetName, pointSetDescription, providerUrl, metadataManager, this.webgl, this.astroSphere.healpixGrid.visibleTilesManager);
4871
5035
  }
4872
5036
  showTerraPointSet(pointSet) {
4873
- this.astroSphere.showCatalogue(pointSet);
5037
+ this.astroSphere.showTerraPointSet(pointSet);
4874
5038
  }
4875
5039
  hideTerraPointSet(pointSet, isVisible) {
4876
5040
  pointSet.setIsVisible(isVisible);
4877
5041
  }
4878
5042
  deleteTerraPointSet(pointSet) {
4879
- this.astroSphere.deleteCatalogue(pointSet);
5043
+ this.astroSphere.deleteTerraPointSet(pointSet);
4880
5044
  }
4881
5045
  createTerraFootprintSet(footprintSetName, footprintSetDescription, providerUrl, metadataManager) {
4882
5046
  return new TerraFootprintSetGL_js_1.TerraFootprintSetGL(footprintSetName, footprintSetDescription, providerUrl, metadataManager, this.webgl);
4883
5047
  }
4884
5048
  showTerraFootprintSet(footprintSet) {
4885
- this.astroSphere.showFootprintSet(footprintSet);
5049
+ this.astroSphere.showTerraFootprintSet(footprintSet);
4886
5050
  }
4887
5051
  hideTerraFootprintSet(footprintSet, isVisible) {
4888
5052
  footprintSet.setIsVisible(isVisible);
4889
5053
  }
4890
5054
  deleteTerraFootprintSet(footprintSet) {
4891
- this.astroSphere.deleteFootprintSet(footprintSet);
5055
+ this.astroSphere.deleteTerraFootprintSet(footprintSet);
4892
5056
  }
4893
5057
  createTerraPolylineSet(polylineSetName, polylineSetDescription, providerUrl, metadataManager) {
4894
5058
  return new TerraPolylineSetGL_js_1.TerraPolylineSetGL(polylineSetName, polylineSetDescription, providerUrl, metadataManager, this.webgl);
@@ -4941,6 +5105,12 @@ class AstroViewer {
4941
5105
  getDefaultHiPSURL() {
4942
5106
  return Config_js_1.bootSetup.defaultHipsUrl;
4943
5107
  }
5108
+ setActiveDomain(domain) {
5109
+ this.astroSphere.setActiveDomain(domain);
5110
+ }
5111
+ getActiveDomain() {
5112
+ return this.astroSphere.activeDomain;
5113
+ }
4944
5114
  activateHiPS(hipsDescriptor) {
4945
5115
  this.astroSphere.activateHiPS(hipsDescriptor);
4946
5116
  }
@@ -4954,9 +5124,37 @@ class AstroViewer {
4954
5124
  activateWMTS(config) {
4955
5125
  this.astroSphere.activateWMTS(config);
4956
5126
  }
5127
+ addXYZRasterOverlay(config) {
5128
+ const descriptor = new XYZMapDescriptor_js_1.XYZMapDescriptor(config.name ?? "XYZ Earth Raster Overlay", config.urlTemplate, config.minZoom ?? 0, config.maxZoom ?? 8, config.segmentsPerSide ?? 48, config.maxCachedTiles ?? 384, 8, config.urlResolver);
5129
+ return this.astroSphere.addXYZRasterOverlay(descriptor);
5130
+ }
5131
+ addWMTSRasterOverlay(config) {
5132
+ return this.astroSphere.addWMTSRasterOverlay(config);
5133
+ }
5134
+ getEarthRasterOverlays() {
5135
+ return this.astroSphere.getEarthRasterOverlays();
5136
+ }
5137
+ setEarthRasterOverlayOpacity(id, opacity) {
5138
+ this.astroSphere.setEarthRasterOverlayOpacity(id, opacity);
5139
+ }
5140
+ setEarthRasterOverlayVisible(id, visible) {
5141
+ this.astroSphere.setEarthRasterOverlayVisible(id, visible);
5142
+ }
5143
+ removeEarthRasterOverlay(id) {
5144
+ this.astroSphere.removeEarthRasterOverlay(id);
5145
+ }
5146
+ removeAllEarthRasterOverlays() {
5147
+ this.astroSphere.removeAllEarthRasterOverlays();
5148
+ }
4957
5149
  activateMeshHiPS(config) {
4958
5150
  this.astroSphere.activateMeshHiPS(new MeshHiPSDescriptor_js_1.MeshHiPSDescriptor(config));
4959
5151
  }
5152
+ setMeshHiPSColor(color) {
5153
+ this.astroSphere.setMeshHiPSColor(color);
5154
+ }
5155
+ setMeshHiPSWireframe(wireframe) {
5156
+ this.astroSphere.setMeshHiPSWireframe(wireframe);
5157
+ }
4960
5158
  setXYZMaxConcurrentRequests(value) {
4961
5159
  XYZTileRequestScheduler_js_1.xyzTileRequestScheduler.setMaxConcurrent(value);
4962
5160
  }
@@ -5760,6 +5958,22 @@ class Camera {
5760
5958
  }
5761
5959
  return [inv[12], inv[13], inv[14]];
5762
5960
  }
5961
+ getViewState() {
5962
+ return {
5963
+ position: [this.cam_pos[0], this.cam_pos[1], this.cam_pos[2]],
5964
+ viewMatrix: gl_matrix_1.mat4.clone(this.vMatrix),
5965
+ translationMatrix: gl_matrix_1.mat4.clone(this.T),
5966
+ rotationMatrix: gl_matrix_1.mat4.clone(this.R),
5967
+ };
5968
+ }
5969
+ restoreViewState(state) {
5970
+ this.cancelFlyTo();
5971
+ this.cam_pos = gl_matrix_1.vec3.fromValues(...state.position);
5972
+ this.vMatrix = gl_matrix_1.mat4.clone(state.viewMatrix);
5973
+ this.T = gl_matrix_1.mat4.clone(state.translationMatrix);
5974
+ this.R = gl_matrix_1.mat4.clone(state.rotationMatrix);
5975
+ this.move = gl_matrix_1.vec3.create();
5976
+ }
5763
5977
  setCameraMatrix(viewMatrix) {
5764
5978
  this.vMatrix = viewMatrix;
5765
5979
  }
@@ -5977,7 +6191,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5977
6191
  return (mod && mod.__esModule) ? mod : { "default": mod };
5978
6192
  };
5979
6193
  Object.defineProperty(exports, "__esModule", ({ value: true }));
5980
- exports.Footprint = exports.Source = exports.MeshHiPSDescriptor = exports.MeshHiPS = exports.WMTSAdapter = exports.XYZMap = exports.HiPS = exports.createColorMapFromSamples = exports.COLOR_MAP_SAMPLE_COUNT = exports.ColorMaps = exports.GeoJSONParser = exports.CoordsType = exports.FoVUtils = exports.CartesianOpts = exports.PointInitOpts = exports.AstroOpts = exports.SphericalOpts = exports.Point = exports.ColumnType = exports.MetadataInit = exports.MetadataColumn = exports.MetadataManager = exports.ObservationTrackViewerAdapter = exports.ObservationTrackTimeline = exports.footprintToRing = exports.createObservationTrackTimeline = exports.SensorConeGL = exports.SatelliteObjectGL = exports.TerraPolylineSetGL = exports.TerraFootprintSetGL = exports.TerraPointSetGL = exports.CatalogueGL = exports.FootprintSetGL = exports.HoveredFootprintDetail = exports.SphereFoV = exports.FoV = exports.HiPSDescriptor = exports.AstroViewer = void 0;
6194
+ exports.Footprint = exports.Source = exports.MeshHiPSDescriptor = exports.MeshHiPS = exports.WMTSAdapter = exports.XYZMap = exports.HiPS = exports.createColorMapFromSamples = exports.COLOR_MAP_SAMPLE_COUNT = exports.ColorMaps = exports.GeoJSONParser = exports.CoordsType = exports.FoVUtils = exports.decDMSToDeg = exports.raHMSToDeg = exports.CartesianOpts = exports.PointInitOpts = exports.AstroOpts = exports.SphericalOpts = exports.Point = exports.ColumnType = exports.MetadataInit = exports.MetadataColumn = exports.MetadataManager = exports.ObservationTrackViewerAdapter = exports.ObservationTrackTimeline = exports.footprintToRing = exports.createObservationTrackTimeline = exports.SensorConeGL = exports.SatelliteObjectGL = exports.TerraPolylineSetGL = exports.TerraFootprintSetGL = exports.TerraPointSetGL = exports.CatalogueGL = exports.FootprintSetGL = exports.HoveredFootprintDetail = exports.SphereFoV = exports.FoV = exports.HiPSDescriptor = exports.AstroViewer = void 0;
5981
6195
  var AstroViewer_js_1 = __webpack_require__(772);
5982
6196
  Object.defineProperty(exports, "AstroViewer", ({ enumerable: true, get: function () { return AstroViewer_js_1.AstroViewer; } }));
5983
6197
  var HiPSDescriptor_js_1 = __webpack_require__(5087);
@@ -6018,6 +6232,9 @@ Object.defineProperty(exports, "SphericalOpts", ({ enumerable: true, get: functi
6018
6232
  Object.defineProperty(exports, "AstroOpts", ({ enumerable: true, get: function () { return Point_js_1.AstroOpts; } }));
6019
6233
  Object.defineProperty(exports, "PointInitOpts", ({ enumerable: true, get: function () { return Point_js_1.PointInitOpts; } }));
6020
6234
  Object.defineProperty(exports, "CartesianOpts", ({ enumerable: true, get: function () { return Point_js_1.CartesianOpts; } }));
6235
+ var Utils_js_1 = __webpack_require__(7930);
6236
+ Object.defineProperty(exports, "raHMSToDeg", ({ enumerable: true, get: function () { return Utils_js_1.raHMSToDeg; } }));
6237
+ Object.defineProperty(exports, "decDMSToDeg", ({ enumerable: true, get: function () { return Utils_js_1.decDMSToDeg; } }));
6021
6238
  var FoVUtils_js_1 = __webpack_require__(8083);
6022
6239
  Object.defineProperty(exports, "FoVUtils", ({ enumerable: true, get: function () { return FoVUtils_js_1.FoVUtils; } }));
6023
6240
  var CoordsType_js_1 = __webpack_require__(8145);
@@ -8025,7 +8242,7 @@ class Source {
8025
8242
  this._point = in_point;
8026
8243
  this._details = in_details;
8027
8244
  this._shapesize = 16.0;
8028
- this._brightnessFactor = -99;
8245
+ this._brightnessFactor = 3.0;
8029
8246
  this.computeHealpixPixel();
8030
8247
  }
8031
8248
  getDetailByindex(index) {
@@ -8314,12 +8531,13 @@ const Utils_js_1 = __webpack_require__(7930);
8314
8531
  const CatalogueShaderProgram_js_1 = __webpack_require__(3559);
8315
8532
  const MetadataManager_js_1 = __webpack_require__(5403);
8316
8533
  const gl_matrix_1 = __webpack_require__(3890);
8534
+ const healpix_1 = __webpack_require__(4851);
8317
8535
  const Global_js_1 = __importDefault(__webpack_require__(4382));
8318
8536
  class CatalogueGL {
8319
8537
  _kind = "CatalogueGL";
8320
8538
  static ELEM_SIZE = 6;
8321
8539
  static BYTES_X_ELEM = new Float32Array().BYTES_PER_ELEMENT;
8322
- static STANDARD_SHAPE_SIZE = 10.0;
8540
+ static STANDARD_SHAPE_SIZE = 16.0;
8323
8541
  static STANDARD_SHAPE_HUE = 3.0;
8324
8542
  _ready;
8325
8543
  _name;
@@ -8562,7 +8780,7 @@ class CatalogueGL {
8562
8780
  getColumnIndex(columnsmeta, columnName) {
8563
8781
  if (!columnName)
8564
8782
  return -1;
8565
- return columnsmeta.find((column) => column.name === columnName)?.index ?? -1;
8783
+ return (columnsmeta.find((column) => column.name === columnName)?.index ?? -1);
8566
8784
  }
8567
8785
  readCell(row, columnsmeta, columnName) {
8568
8786
  const idx = this.getColumnIndex(columnsmeta, columnName);
@@ -8575,7 +8793,9 @@ class CatalogueGL {
8575
8793
  const src = String(rawSrc ?? "").trim();
8576
8794
  if (!src)
8577
8795
  return undefined;
8578
- const rawKind = String(this.readCell(row, columnsmeta, mediaColumns.type) ?? "sprite").trim().toLowerCase();
8796
+ const rawKind = String(this.readCell(row, columnsmeta, mediaColumns.type) ?? "sprite")
8797
+ .trim()
8798
+ .toLowerCase();
8579
8799
  const kind = rawKind === "model"
8580
8800
  ? "model"
8581
8801
  : rawKind === "image"
@@ -8595,7 +8815,9 @@ class CatalogueGL {
8595
8815
  src,
8596
8816
  scale: Number.isFinite(scale) && scale > 0 ? scale : undefined,
8597
8817
  rotationDeg: Number.isFinite(rotationDeg) ? rotationDeg : undefined,
8598
- opacity: Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : undefined,
8818
+ opacity: Number.isFinite(opacity)
8819
+ ? Math.max(0, Math.min(1, opacity))
8820
+ : undefined,
8599
8821
  };
8600
8822
  }
8601
8823
  clearSources() {
@@ -8886,33 +9108,46 @@ class CatalogueGL {
8886
9108
  this._webgl.bufferData(this._webgl.ARRAY_BUFFER, this.vertexCataloguePosition, this._webgl.STATIC_DRAW);
8887
9109
  this._bufferInitialised = true;
8888
9110
  }
8889
- getSelectionRadius() {
8890
- const order = this._visibleTilesManager.getVisibleOrder();
8891
- switch (order) {
8892
- case 0:
8893
- case 1:
8894
- case 2:
8895
- // return 0.005;
8896
- return 0.01;
8897
- case 3:
8898
- // return 0.001;
8899
- case 4:
8900
- // return 0.0009;
8901
- case 5:
8902
- // return 0.0005;
8903
- return 0.005;
8904
- case 6:
8905
- // return 0.0001;
8906
- case 7:
8907
- // return 0.00009;
8908
- case 8:
8909
- // return 0.00005;
8910
- return 0.001;
8911
- case 9:
8912
- return 0.0005;
8913
- default:
8914
- return 0.0001;
9111
+ static MIN_HIT_RADIUS_PX = 6;
9112
+ static HIT_PADDING_PX = 3;
9113
+ static CANDIDATE_RADIUS_PX = 16;
9114
+ getCanvas() {
9115
+ return this._webgl.canvas;
9116
+ }
9117
+ getHitRadiusPx(source) {
9118
+ const markerSize = source.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
9119
+ return Math.max(CatalogueGL.MIN_HIT_RADIUS_PX, markerSize / 2 + CatalogueGL.HIT_PADDING_PX);
9120
+ }
9121
+ getCandidateSearchRadiusRad(pMatrix) {
9122
+ const canvas = this._webgl.canvas;
9123
+ const width = Math.max(1, canvas.clientWidth);
9124
+ const height = Math.max(1, canvas.clientHeight);
9125
+ // pMatrix[0] and pMatrix[5] are the perspective scale factors for X/Y.
9126
+ // Convert a small screen-space radius to a conservative angular radius.
9127
+ const fovXRad = 2 * Math.atan(1 / Math.abs(pMatrix[0]));
9128
+ const fovYRad = 2 * Math.atan(1 / Math.abs(pMatrix[5]));
9129
+ const radPerPixel = Math.max(fovXRad / width, fovYRad / height);
9130
+ return CatalogueGL.CANDIDATE_RADIUS_PX * radPerPixel;
9131
+ }
9132
+ projectPointToScreen(point, mvp, width, height) {
9133
+ const projected = gl_matrix_1.vec4.fromValues(point.x, point.y, point.z, 1);
9134
+ gl_matrix_1.vec4.transformMat4(projected, projected, mvp);
9135
+ if (projected[3] <= 0)
9136
+ return null;
9137
+ const ndcX = projected[0] / projected[3];
9138
+ const ndcY = projected[1] / projected[3];
9139
+ return [(ndcX * 0.5 + 0.5) * width, (1 - (ndcY * 0.5 + 0.5)) * height];
9140
+ }
9141
+ clearSelection() {
9142
+ for (const idx of this.selectedIndexes) {
9143
+ const base = idx * CatalogueGL.ELEM_SIZE;
9144
+ if (base + 4 >= this.vertexCataloguePosition.length)
9145
+ continue;
9146
+ this.vertexCataloguePosition[base + 3] = 0.0;
9147
+ this.vertexCataloguePosition[base + 4] =
9148
+ this._sources[idx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8915
9149
  }
9150
+ this.selectedIndexes = [];
8916
9151
  }
8917
9152
  setSelectedIndexes(selectedIndex) {
8918
9153
  selectedIndex.forEach((idx) => {
@@ -8939,8 +9174,8 @@ class CatalogueGL {
8939
9174
  * Run click-picking and update selection with the nearest candidate in current pixel.
8940
9175
  * Returns the selected source or null if no source was hit.
8941
9176
  */
8942
- getSourcesFromPointer(in_mouseHelper) {
8943
- const pickedIndexes = this.checkClicking(in_mouseHelper);
9177
+ getSourcesFromPointer(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9178
+ const pickedIndexes = this.checkClicking(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
8944
9179
  if (!pickedIndexes.length) {
8945
9180
  return {
8946
9181
  sources: [],
@@ -8959,8 +9194,8 @@ class CatalogueGL {
8959
9194
  * Run click-picking and update selection with the nearest candidate in current pixel.
8960
9195
  * Returns the selected source or null if no source was hit.
8961
9196
  */
8962
- selectPrimarySourceFromClick(in_mouseHelper) {
8963
- const picked = this.getSourcesFromPointer(in_mouseHelper);
9197
+ selectPrimarySourceFromClick(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9198
+ const picked = this.getSourcesFromPointer(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
8964
9199
  const clickedIndexes = picked?.pickedIndexes ?? [];
8965
9200
  // if (!clickedIndexes.length) {
8966
9201
  // this.setSelectedIndexes([]);
@@ -8996,42 +9231,65 @@ class CatalogueGL {
8996
9231
  const idx = this.hoveredIndexes[0];
8997
9232
  return this._sources[idx] ?? null;
8998
9233
  }
8999
- findNearestSourceIndex(in_mouseHelper) {
9000
- if (in_mouseHelper.x == null ||
9001
- in_mouseHelper.y == null ||
9002
- in_mouseHelper.z == null) {
9234
+ findNearestSourceIndex(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9235
+ if (in_mouseHelper.xyz == null)
9003
9236
  return null;
9237
+ const healpix = Global_js_1.default.getHealpix(Global_js_1.default.selectionOrder);
9238
+ const mouseVec = new healpix_1.Vec3(...in_mouseHelper.xyz);
9239
+ const mousePointing = new healpix_1.Pointing(mouseVec, false);
9240
+ const searchRadiusRad = this.getCandidateSearchRadiusRad(pMatrix);
9241
+ const rangeSet = healpix.queryDiscInclusive(mousePointing, searchRadiusRad, 4);
9242
+ const pixels = rangeSet.r;
9243
+ const candidateIndexes = new Set();
9244
+ for (const pixel of pixels) {
9245
+ const indexes = this._healpixDensityMap.get(pixel);
9246
+ if (!indexes)
9247
+ continue;
9248
+ indexes.forEach((idx) => candidateIndexes.add(idx));
9004
9249
  }
9005
- const mousePix = in_mouseHelper.computeNpix();
9006
- if (mousePix == null)
9250
+ if (!candidateIndexes.size)
9251
+ return null;
9252
+ const canvas = this._webgl.canvas;
9253
+ const width = canvas.clientWidth;
9254
+ const height = canvas.clientHeight;
9255
+ if (!width || !height)
9007
9256
  return null;
9008
- const candidates = this._healpixDensityMap.get(mousePix);
9009
- if (!candidates?.length)
9257
+ const modelView = gl_matrix_1.mat4.create();
9258
+ const mvp = gl_matrix_1.mat4.create();
9259
+ gl_matrix_1.mat4.multiply(modelView, vMatrix, in_mMatrix);
9260
+ gl_matrix_1.mat4.multiply(mvp, pMatrix, modelView);
9261
+ const mousePoint = new Point_js_1.Point({
9262
+ x: in_mouseHelper.xyz[0],
9263
+ y: in_mouseHelper.xyz[1],
9264
+ z: in_mouseHelper.xyz[2],
9265
+ }, CoordsType_js_1.CoordsType.CARTESIAN);
9266
+ const mouseScreen = this.projectPointToScreen(mousePoint, mvp, width, height);
9267
+ if (!mouseScreen)
9010
9268
  return null;
9011
- const selR = this.getSelectionRadius();
9012
9269
  let nearestIndex = null;
9013
- let nearestDistance = Number.POSITIVE_INFINITY;
9014
- for (const sourceIdx of candidates) {
9270
+ let nearestDistancePx = Number.POSITIVE_INFINITY;
9271
+ for (const sourceIdx of candidateIndexes) {
9015
9272
  const source = this._sources[sourceIdx];
9016
9273
  if (!source)
9017
9274
  continue;
9018
- const dx = source.point.x - in_mouseHelper.x;
9019
- const dy = source.point.y - in_mouseHelper.y;
9020
- const dz = source.point.z - in_mouseHelper.z;
9021
- const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
9022
- if (dist <= selR && dist < nearestDistance) {
9023
- nearestDistance = dist;
9275
+ const sourceScreen = this.projectPointToScreen(source.point, mvp, width, height);
9276
+ if (!sourceScreen)
9277
+ continue;
9278
+ const distancePx = Math.hypot(sourceScreen[0] - mouseScreen[0], sourceScreen[1] - mouseScreen[1]);
9279
+ if (distancePx <= this.getHitRadiusPx(source) &&
9280
+ distancePx < nearestDistancePx) {
9281
+ nearestDistancePx = distancePx;
9024
9282
  nearestIndex = sourceIdx;
9025
9283
  }
9026
9284
  }
9027
9285
  return nearestIndex;
9028
9286
  }
9029
- checkClicking(in_mouseHelper) {
9030
- const nearestIndex = this.findNearestSourceIndex(in_mouseHelper);
9287
+ checkClicking(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9288
+ const nearestIndex = this.findNearestSourceIndex(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
9031
9289
  return nearestIndex == null ? [] : [nearestIndex];
9032
9290
  }
9033
- checkHovering(in_mouseHelper) {
9034
- const nearestIndex = this.findNearestSourceIndex(in_mouseHelper);
9291
+ checkHovering(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9292
+ const nearestIndex = this.findNearestSourceIndex(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
9035
9293
  return nearestIndex == null ? [] : [nearestIndex];
9036
9294
  }
9037
9295
  /**
@@ -9067,6 +9325,13 @@ class CatalogueGL {
9067
9325
  if (this._catalogueShaderProgram.locations.color) {
9068
9326
  this._webgl.uniform4f(this._catalogueShaderProgram.locations.color, rgb[0], rgb[1], rgb[2], 1.0);
9069
9327
  }
9328
+ const interactionColors = (0, Utils_js_1.interactionColorsFromHex)(this._shapeColor);
9329
+ if (this._catalogueShaderProgram.locations.hoverColor) {
9330
+ this._webgl.uniform4f(this._catalogueShaderProgram.locations.hoverColor, ...interactionColors.hover, 1.0);
9331
+ }
9332
+ if (this._catalogueShaderProgram.locations.selectedColor) {
9333
+ this._webgl.uniform4f(this._catalogueShaderProgram.locations.selectedColor, ...interactionColors.selected, 1.0);
9334
+ }
9070
9335
  // selected flags
9071
9336
  for (let s = 0; s < this.selectedIndexes.length; s++) {
9072
9337
  const idx = this.selectedIndexes[s];
@@ -9077,7 +9342,8 @@ class CatalogueGL {
9077
9342
  // clear old hovered
9078
9343
  for (let k = 0; k < this.hoveredIndexes.length; k++) {
9079
9344
  const base = this.hoveredIndexes[k] * CatalogueGL.ELEM_SIZE;
9080
- // if (this.vertexCataloguePosition[base + 3] == 2.0) continue; // selected, skip hover
9345
+ if (this.selectedIndexes.includes(this.hoveredIndexes[k]))
9346
+ continue;
9081
9347
  this.vertexCataloguePosition[base + 3] = 0.0; // not hovered
9082
9348
  this.vertexCataloguePosition[base + 4] =
9083
9349
  this._sources[this.hoveredIndexes[k]].shapeSize; // size
@@ -9091,7 +9357,7 @@ class CatalogueGL {
9091
9357
  // this.vertexCataloguePosition[base + 3] = 0.0; // not hovered
9092
9358
  // this.vertexCataloguePosition[base + 4] = this._sources[this.hoveredIndexes[k]].shapeSize; // size
9093
9359
  // }
9094
- this.hoveredIndexes = this.checkHovering(in_mouseHelper);
9360
+ this.hoveredIndexes = this.checkHovering(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
9095
9361
  // // new hovered
9096
9362
  // for (let i = 0; i < this.hoveredIndexes.length; i++) {
9097
9363
  // const idx = this.hoveredIndexes[i];
@@ -9105,7 +9371,8 @@ class CatalogueGL {
9105
9371
  for (let i = 0; i < this.hoveredIndexes.length; i++) {
9106
9372
  const idx = this.hoveredIndexes[i];
9107
9373
  const base = idx * CatalogueGL.ELEM_SIZE;
9108
- // if (this.vertexCataloguePosition[base + 3] == 2.0) continue; // selected, skip hover
9374
+ if (this.selectedIndexes.includes(idx))
9375
+ continue;
9109
9376
  this.vertexCataloguePosition[base + 3] = 1.0; // hovered
9110
9377
  this.vertexCataloguePosition[base + 4] = this._sources[idx].shapeSize; // size
9111
9378
  }
@@ -9513,6 +9780,7 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9513
9780
  _latLonGrid;
9514
9781
  _colorMapIdx = 0;
9515
9782
  _colorMap = ColorMaps_js_1.ColorMaps['native'];
9783
+ _opacity = 1;
9516
9784
  constructor(radius, position, xrad, yrad, descriptor, webgl, gridLabelContainers) {
9517
9785
  super(radius, position, xrad, yrad, descriptor.name, webgl, false);
9518
9786
  this._descriptor = descriptor;
@@ -9527,6 +9795,10 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9527
9795
  const fov = 180;
9528
9796
  this._zoom = XYZFoVHelper_js_1.xyzFovHelper.getZoom(fov);
9529
9797
  }
9798
+ setOpacity(opacity) {
9799
+ this._opacity = Math.min(1, Math.max(0, opacity));
9800
+ this._xyzShaderProgram.setOpacity(this._opacity);
9801
+ }
9530
9802
  changeColorMap(colorMap) {
9531
9803
  this._colorMap = colorMap;
9532
9804
  switch (colorMap.name) {
@@ -9574,6 +9846,9 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9574
9846
  initShaders() {
9575
9847
  this._xyzShaderProgram.enableProgram();
9576
9848
  }
9849
+ clearLonLatGridLabels() {
9850
+ this._latLonGrid.clearLabels();
9851
+ }
9577
9852
  isLonLatGridVisible() {
9578
9853
  return this._latLonGrid.isVisible();
9579
9854
  }
@@ -9588,7 +9863,7 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9588
9863
  // this._zoom = this.resolveVisibleZoom(fov)
9589
9864
  this._zoom = XYZFoVHelper_js_1.xyzFovHelper.getZoom(fov);
9590
9865
  }
9591
- draw(input) {
9866
+ draw(input, asOverlay = false) {
9592
9867
  const vMatrix = input.camera.getCameraMatrix();
9593
9868
  if (!vMatrix)
9594
9869
  return;
@@ -9598,6 +9873,18 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9598
9873
  this.refresh(input);
9599
9874
  const mMatrix = this.getModelMatrix();
9600
9875
  this._xyzShaderProgram.setRuntimeColorMap(this._colorMap);
9876
+ this._xyzShaderProgram.setOpacity(this._opacity);
9877
+ const depthTestWasEnabled = this._webgl.isEnabled(this._webgl.DEPTH_TEST);
9878
+ const blendWasEnabled = this._webgl.isEnabled(this._webgl.BLEND);
9879
+ const blendSrcRgb = this._webgl.getParameter(this._webgl.BLEND_SRC_RGB);
9880
+ const blendDstRgb = this._webgl.getParameter(this._webgl.BLEND_DST_RGB);
9881
+ const blendSrcAlpha = this._webgl.getParameter(this._webgl.BLEND_SRC_ALPHA);
9882
+ const blendDstAlpha = this._webgl.getParameter(this._webgl.BLEND_DST_ALPHA);
9883
+ if (asOverlay) {
9884
+ this._webgl.disable(this._webgl.DEPTH_TEST);
9885
+ this._webgl.enable(this._webgl.BLEND);
9886
+ this._webgl.blendFunc(this._webgl.SRC_ALPHA, this._webgl.ONE_MINUS_SRC_ALPHA);
9887
+ }
9601
9888
  const tileSelection = this._visibleTilesManager.computeVisibleTiles(this._zoom, this, this._webgl, input.camera, input.pMatrix);
9602
9889
  const visibleTiles = tileSelection.visibleTiles;
9603
9890
  const ancestorsMap = tileSelection.ancestorsMap;
@@ -9615,7 +9902,20 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9615
9902
  const ancestorTile = this.findBestAvailableAncestor(tile.coord);
9616
9903
  ancestorTile?.draw(tileSelection.currentZoom, [tile.coord], ancestorsMap, pMatrix, vMatrix, mMatrix, this._colorMapIdx);
9617
9904
  }
9618
- this._latLonGrid.draw(input);
9905
+ if (asOverlay) {
9906
+ if (depthTestWasEnabled)
9907
+ this._webgl.enable(this._webgl.DEPTH_TEST);
9908
+ else
9909
+ this._webgl.disable(this._webgl.DEPTH_TEST);
9910
+ this._webgl.blendFuncSeparate(blendSrcRgb, blendDstRgb, blendSrcAlpha, blendDstAlpha);
9911
+ if (blendWasEnabled)
9912
+ this._webgl.enable(this._webgl.BLEND);
9913
+ else
9914
+ this._webgl.disable(this._webgl.BLEND);
9915
+ }
9916
+ else {
9917
+ this._latLonGrid.draw(input);
9918
+ }
9619
9919
  }
9620
9920
  createTile(coord) {
9621
9921
  return new XYZAnchestorTile_js_1.XYZAnchestorTile(coord, this.resolveTileUrl(coord), this._webgl, this._xyzShaderProgram, this._meshBuilder, this._descriptor.segmentsPerSide);
@@ -10909,6 +11209,10 @@ class FootprintSetGL {
10909
11209
  }
10910
11210
  return clickedIndexes;
10911
11211
  }
11212
+ clearSelection() {
11213
+ this.selectedIndexes = [];
11214
+ this.refreshSelectedFootprints();
11215
+ }
10912
11216
  setSelectedIndexes(selectedIndex) {
10913
11217
  selectedIndex.forEach((idx) => {
10914
11218
  if (idx < 0 || idx >= this.footprintPolygons.length)
@@ -11210,9 +11514,10 @@ class FootprintSetGL {
11210
11514
  if (in_mouseHelper != null && in_mouseHelper.xyz != this.oldMouseCoords) {
11211
11515
  this.checkSelection(in_mouseHelper);
11212
11516
  }
11517
+ const interactionColors = (0, Utils_js_1.interactionColorsFromHex)(this._shapeColor);
11213
11518
  if (this._hoveredFootprints.length > 0) {
11214
11519
  // TODO POINT_SIZE doesn't have any effect on line thickness!! it only applies to points
11215
- const rgb = (0, Utils_js_1.colorHex2RGB)("#00FF00");
11520
+ const rgb = interactionColors.hover;
11216
11521
  const alpha = 1.0;
11217
11522
  this._webgl.uniform4f(this._footprintShaderProgram.locations.color, rgb[0], rgb[1], rgb[2], alpha);
11218
11523
  this._webgl.uniform1f(this._footprintShaderProgram.locations.pointSize, 14.0); // <--- POINT_SIZE in LINE_LOOP is not applicable
@@ -11227,7 +11532,7 @@ class FootprintSetGL {
11227
11532
  this._webgl.drawElements(this._webgl.LINE_LOOP, this.hoveredVertexPosition.length / 3 + this.nHoveredPrimitiveFlags, this._webgl.UNSIGNED_INT, 0);
11228
11533
  }
11229
11534
  if (this._selectedFootprints.length > 0) {
11230
- const rgb = (0, Utils_js_1.colorHex2RGB)("#ECB462");
11535
+ const rgb = interactionColors.selected;
11231
11536
  const alpha = 1.0;
11232
11537
  this._webgl.uniform4f(this._footprintShaderProgram.locations.color, rgb[0], rgb[1], rgb[2], alpha);
11233
11538
  this._webgl.uniform1f(this._footprintShaderProgram.locations.pointSize, 14.0); // <--- POINT_SIZE in LINE_LOOP is not applicable
@@ -11240,6 +11545,11 @@ class FootprintSetGL {
11240
11545
  this._webgl.bufferData(this._webgl.ELEMENT_ARRAY_BUFFER, this.selectedElementIndexes, this._webgl.STATIC_DRAW);
11241
11546
  // this._gl.drawElements (this._gl.LINE_LOOP, this._selectedVertexPosition.length / 3 + this._nSlectedPrimitiveFlags,this._gl.UNSIGNED_SHORT, 0);
11242
11547
  this._webgl.drawElements(this._webgl.LINE_LOOP, this.selectedVertexPosition.length / 3 + this.nSlectedPrimitiveFlags, this._webgl.UNSIGNED_INT, 0);
11548
+ // Keep selection visually distinct from hover without relying on
11549
+ // non-portable line widths. Reuse the selected geometry as small
11550
+ // vertex markers; POINT_SIZE is supported for POINTS in WebGL2.
11551
+ this._webgl.uniform1f(this._footprintShaderProgram.locations.pointSize, 4.0);
11552
+ this._webgl.drawElements(this._webgl.POINTS, this.selectedVertexPosition.length / 3 + this.nSlectedPrimitiveFlags, this._webgl.UNSIGNED_INT, 0);
11243
11553
  }
11244
11554
  this._webgl.bindBuffer(this._webgl.ARRAY_BUFFER, this.vertexCataloguePositionBuffer);
11245
11555
  this._webgl.vertexAttribPointer(this._footprintShaderProgram.locations.position, FootprintSetGL.ELEM_SIZE, this._webgl.FLOAT, false, FootprintSetGL.BYTES_X_ELEM * FootprintSetGL.ELEM_SIZE, 0);
@@ -11473,6 +11783,9 @@ class EquatorialGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
11473
11783
  gl.uniform4f(uColor, rgb[0], rgb[1], rgb[2], 1.0);
11474
11784
  }
11475
11785
  }
11786
+ clearLabels() {
11787
+ this.gridText.resetDivSets();
11788
+ }
11476
11789
  isVisible() {
11477
11790
  return this.showGrid;
11478
11791
  }
@@ -12069,6 +12382,9 @@ class HealpixGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12069
12382
  this.gridText.resetDivSets();
12070
12383
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
12071
12384
  }
12385
+ clearLabels() {
12386
+ this.gridText.resetDivSets();
12387
+ }
12072
12388
  get visibleorder() {
12073
12389
  return this._visibleorder;
12074
12390
  }
@@ -12303,6 +12619,9 @@ class LatLonGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12303
12619
  gl.uniform4f(uColor, rgb[0], rgb[1], rgb[2], 1.0);
12304
12620
  }
12305
12621
  }
12622
+ clearLabels() {
12623
+ this.gridText.resetDivSets();
12624
+ }
12306
12625
  draw(input) {
12307
12626
  if (!this._showGrid) {
12308
12627
  this.gridText.resetDivSets();
@@ -14971,6 +15290,8 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14971
15290
  _currentOrder;
14972
15291
  _visibleTiles = [];
14973
15292
  _coverageTiles = [];
15293
+ _color;
15294
+ _wireframe;
14974
15295
  constructor(radius, position, xrad, yrad, _descriptor, webgl, _healpixGrid) {
14975
15296
  super(radius, position, xrad, yrad, _descriptor.name, webgl, false);
14976
15297
  this._descriptor = _descriptor;
@@ -14979,6 +15300,8 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14979
15300
  this._shaderProgram = new MeshHiPSShaderProgram_js_1.MeshHiPSShaderProgram(webgl);
14980
15301
  this._shaderProgram.enableProgram();
14981
15302
  this._currentOrder = _descriptor.selectedOrder;
15303
+ this._color = [..._descriptor.color];
15304
+ this._wireframe = _descriptor.wireframe;
14982
15305
  }
14983
15306
  get currentOrder() {
14984
15307
  return this._currentOrder;
@@ -15001,6 +15324,12 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15001
15324
  getProperty(key) {
15002
15325
  return this._descriptor.getProperty(key);
15003
15326
  }
15327
+ setColor(color) {
15328
+ this._color = [...color];
15329
+ }
15330
+ setWireframe(wireframe) {
15331
+ this._wireframe = wireframe;
15332
+ }
15004
15333
  refreshOrder(fovDeg) {
15005
15334
  if (this._descriptor.fixedOrder) {
15006
15335
  this._currentOrder = this._descriptor.selectedOrder;
@@ -15040,7 +15369,7 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
15040
15369
  for (const coord of byOrder.get(order) ?? []) {
15041
15370
  this._tiles
15042
15371
  .get(this.tileKey(coord))
15043
- ?.draw(pMatrix, vMatrix, mMatrix, this._descriptor.color, this._descriptor.wireframe);
15372
+ ?.draw(pMatrix, vMatrix, mMatrix, this._color, this._wireframe);
15044
15373
  }
15045
15374
  }
15046
15375
  if (wasCullFace)
@@ -16831,6 +17160,7 @@ exports.TerraFootprintSetGL = TerraFootprintSetGL;
16831
17160
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16832
17161
  exports.TerraPointSetGL = void 0;
16833
17162
  const CatalogueGL_js_1 = __webpack_require__(1232);
17163
+ const gl_matrix_1 = __webpack_require__(3890);
16834
17164
  const MetadataManager_js_1 = __webpack_require__(5403);
16835
17165
  const Point_js_1 = __webpack_require__(6553);
16836
17166
  const CoordsType_js_1 = __webpack_require__(8145);
@@ -16865,8 +17195,45 @@ class TerraPointSetGL extends CatalogueGL_js_1.CatalogueGL {
16865
17195
  this._ready = true;
16866
17196
  this._bufferInitialised = false;
16867
17197
  }
17198
+ findNearestSourceIndex(inMouseHelper, inMatrix, viewMatrix, projectionMatrix) {
17199
+ if (inMouseHelper.xyz == null)
17200
+ return null;
17201
+ const canvas = this.getCanvas();
17202
+ const width = canvas.clientWidth;
17203
+ const height = canvas.clientHeight;
17204
+ if (!width || !height)
17205
+ return null;
17206
+ const modelView = gl_matrix_1.mat4.create();
17207
+ const mvp = gl_matrix_1.mat4.create();
17208
+ gl_matrix_1.mat4.multiply(modelView, viewMatrix, inMatrix);
17209
+ gl_matrix_1.mat4.multiply(mvp, projectionMatrix, modelView);
17210
+ const mousePoint = new Point_js_1.Point({
17211
+ x: inMouseHelper.xyz[0],
17212
+ y: inMouseHelper.xyz[1],
17213
+ z: inMouseHelper.xyz[2],
17214
+ }, CoordsType_js_1.CoordsType.CARTESIAN);
17215
+ const mouseScreen = this.projectPointToScreen(mousePoint, mvp, width, height);
17216
+ if (!mouseScreen)
17217
+ return null;
17218
+ let nearestIndex = null;
17219
+ let nearestDistancePx = Number.POSITIVE_INFINITY;
17220
+ for (let index = 0; index < this._sources.length; index += 1) {
17221
+ const source = this._sources[index];
17222
+ if (!source)
17223
+ continue;
17224
+ const sourceScreen = this.projectPointToScreen(source.point, mvp, width, height);
17225
+ if (!sourceScreen)
17226
+ continue;
17227
+ const distancePx = Math.hypot(sourceScreen[0] - mouseScreen[0], sourceScreen[1] - mouseScreen[1]);
17228
+ if (distancePx <= this.getHitRadiusPx(source) &&
17229
+ distancePx < nearestDistancePx) {
17230
+ nearestDistancePx = distancePx;
17231
+ nearestIndex = index;
17232
+ }
17233
+ }
17234
+ return nearestIndex;
17235
+ }
16868
17236
  draw(inMatrix, inMouseHelper, viewMatrix, projectionMatrix) {
16869
- this._oldMouseCoords = inMouseHelper?.xyz ?? null;
16870
17237
  super.draw(inMatrix, inMouseHelper, viewMatrix, projectionMatrix);
16871
17238
  }
16872
17239
  }
@@ -17098,6 +17465,8 @@ class CatalogueShaderProgram {
17098
17465
  this._webgl = webgl;
17099
17466
  this.gl_uniforms = {
17100
17467
  vertex_color: 'u_fragcolor',
17468
+ hover_color: 'u_hovercolor',
17469
+ selected_color: 'u_selectedcolor',
17101
17470
  m_perspective: 'uPMatrix',
17102
17471
  m_model_view: 'uMVMatrix'
17103
17472
  };
@@ -17111,6 +17480,8 @@ class CatalogueShaderProgram {
17111
17480
  pMatrix: null,
17112
17481
  mvMatrix: null,
17113
17482
  color: null,
17483
+ hoverColor: null,
17484
+ selectedColor: null,
17114
17485
  position: -1,
17115
17486
  hovered: -1,
17116
17487
  pointSize: -1,
@@ -17160,6 +17531,8 @@ class CatalogueShaderProgram {
17160
17531
  this.locations.pointSize = gl.getAttribLocation(this.shaderProgram, this.gl_attributes.point_size);
17161
17532
  this.locations.brightness = gl.getAttribLocation(this.shaderProgram, this.gl_attributes.point_hue);
17162
17533
  this.locations.color = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.vertex_color);
17534
+ this.locations.hoverColor = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.hover_color);
17535
+ this.locations.selectedColor = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.selected_color);
17163
17536
  }
17164
17537
  enableShaders(pMatrix, modelMatrix, viewMatrix) {
17165
17538
  // const gl = global.gl as GL
@@ -17850,6 +18223,8 @@ class ShaderManager {
17850
18223
  in float v_brightness;
17851
18224
 
17852
18225
  uniform vec4 u_fragcolor;
18226
+ uniform vec4 u_hovercolor;
18227
+ uniform vec4 u_selectedcolor;
17853
18228
 
17854
18229
  out vec4 fragColor;
17855
18230
 
@@ -17906,11 +18281,12 @@ class ShaderManager {
17906
18281
  #endif
17907
18282
 
17908
18283
  if (v_selected == 1.0){
17909
- // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * (alpha);
17910
- fragColor = vec4(1.0, 0.0, 0.0, 1.0) * (alpha);
18284
+ fragColor = u_hovercolor * alpha;
17911
18285
  } else if (v_selected == 2.0){
17912
- // gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0) * (alpha);
17913
- fragColor = vec4(1.0, 1.0, 0.0, 1.0) * (alpha);
18286
+ // Persistent selection: keep the dataset colour as an outer ring
18287
+ // and use the hover colour for the fill. This remains visible for
18288
+ // both light and dark user-selected base colours.
18289
+ fragColor = (r > 0.72 ? u_fragcolor : u_hovercolor) * alpha;
17914
18290
  }else{
17915
18291
  if (r < 0.4) {
17916
18292
  discard;
@@ -18318,6 +18694,7 @@ class XYZShaderProgram {
18318
18694
  _shaderProgram;
18319
18695
  _colorMapBlockIndex = null;
18320
18696
  _colorMapBuffer = null;
18697
+ _opacity = 1;
18321
18698
  _runtimeColorMap;
18322
18699
  _colorMapVariableInfo = {
18323
18700
  r_palette: { index: 0, offset: 0 },
@@ -18332,6 +18709,7 @@ class XYZShaderProgram {
18332
18709
  vMatrix: null,
18333
18710
  sampler: null,
18334
18711
  colorMapIdx: null,
18712
+ opacity: null,
18335
18713
  vertexPositionAttribute: -1,
18336
18714
  textureCoordAttribute: -1,
18337
18715
  };
@@ -18352,6 +18730,9 @@ class XYZShaderProgram {
18352
18730
  enableProgram() {
18353
18731
  this._webgl.useProgram(this.shaderProgram);
18354
18732
  }
18733
+ setOpacity(opacity) {
18734
+ this._opacity = Math.min(1, Math.max(0, opacity));
18735
+ }
18355
18736
  setRuntimeColorMap(colorMap) {
18356
18737
  this._runtimeColorMap = colorMap;
18357
18738
  }
@@ -18364,6 +18745,7 @@ class XYZShaderProgram {
18364
18745
  this.locations.vMatrix = gl.getUniformLocation(program, 'uVMatrix');
18365
18746
  this.locations.sampler = gl.getUniformLocation(program, 'uSampler');
18366
18747
  this.locations.colorMapIdx = gl.getUniformLocation(program, 'cmapIdx');
18748
+ this.locations.opacity = gl.getUniformLocation(program, 'uOpacity');
18367
18749
  this.locations.vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition');
18368
18750
  this.locations.textureCoordAttribute = gl.getAttribLocation(program, 'aTextureCoord');
18369
18751
  gl.uniformMatrix4fv(this.locations.pMatrix, false, pMatrix);
@@ -18371,6 +18753,7 @@ class XYZShaderProgram {
18371
18753
  gl.uniformMatrix4fv(this.locations.mMatrix, false, mMatrix);
18372
18754
  gl.uniform1i(this.locations.sampler, 0);
18373
18755
  gl.uniform1i(this.locations.colorMapIdx, colorMapIdx);
18756
+ gl.uniform1f(this.locations.opacity, this._opacity);
18374
18757
  if (colorMapIdx >= 2) {
18375
18758
  this.uploadColorMap(colorMapIdx);
18376
18759
  }
@@ -18393,6 +18776,7 @@ class XYZShaderProgram {
18393
18776
  in vec2 vTextureCoord;
18394
18777
  uniform sampler2D uSampler;
18395
18778
  uniform int cmapIdx;
18779
+ uniform float uOpacity;
18396
18780
 
18397
18781
  layout (std140) uniform colormap {
18398
18782
  float r_palette[256];
@@ -18407,7 +18791,7 @@ class XYZShaderProgram {
18407
18791
 
18408
18792
  if (cmapIdx == 1) {
18409
18793
  float gray = 0.21 * color.r + 0.71 * color.g + 0.07 * color.b;
18410
- outColor = vec4(vec3(gray), color.a);
18794
+ outColor = vec4(vec3(gray), color.a * uOpacity);
18411
18795
  return;
18412
18796
  }
18413
18797
 
@@ -18420,12 +18804,12 @@ class XYZShaderProgram {
18420
18804
  r_palette[rIndex] / 256.0,
18421
18805
  g_palette[gIndex] / 256.0,
18422
18806
  b_palette[bIndex] / 256.0,
18423
- color.a
18807
+ color.a * uOpacity
18424
18808
  );
18425
18809
  return;
18426
18810
  }
18427
18811
 
18428
- outColor = color;
18812
+ outColor = vec4(color.rgb, color.a * uOpacity);
18429
18813
  }`);
18430
18814
  gl.attachShader(this._shaderProgram, vertexShader);
18431
18815
  gl.attachShader(this._shaderProgram, fragmentShader);
@@ -19636,7 +20020,6 @@ exports["default"] = STCSParser;
19636
20020
  (__unused_webpack_module, exports, __webpack_require__) {
19637
20021
 
19638
20022
  "use strict";
19639
- var __webpack_unused_export__;
19640
20023
 
19641
20024
  /*
19642
20025
  * AstroViewer
@@ -19648,9 +20031,10 @@ var __webpack_unused_export__;
19648
20031
  *
19649
20032
  * See LICENSE.md, LICENSE-AGPL.md, and LICENSE-COMMERCIAL.md for details.
19650
20033
  */
19651
- __webpack_unused_export__ = ({ value: true });
20034
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
19652
20035
  exports.cartesianToSpherical = cartesianToSpherical;
19653
20036
  exports.colorHex2RGB = colorHex2RGB;
20037
+ exports.interactionColorsFromHex = interactionColorsFromHex;
19654
20038
  exports.degToRad = degToRad;
19655
20039
  exports.radToDeg = radToDeg;
19656
20040
  exports.sphericalToAstroDeg = sphericalToAstroDeg;
@@ -19658,6 +20042,8 @@ exports.sphericalToCartesian = sphericalToCartesian;
19658
20042
  exports.astroDegToSpherical = astroDegToSpherical;
19659
20043
  exports.raDegToHMS = raDegToHMS;
19660
20044
  exports.decDegToDMS = decDegToDMS;
20045
+ exports.raHMSToDeg = raHMSToDeg;
20046
+ exports.decDMSToDeg = decDMSToDeg;
19661
20047
  /**
19662
20048
  * @author Fabrizio Giordano (Fab)
19663
20049
  */
@@ -19688,6 +20074,25 @@ function colorHex2RGB(hexColor) {
19688
20074
  const rgb3 = (dec3 / 255).toFixed(2);
19689
20075
  return [parseFloat(rgb1), parseFloat(rgb2), parseFloat(rgb3)];
19690
20076
  }
20077
+ /**
20078
+ * Derive interaction colours from the object's normal colour.
20079
+ * Dark colours move towards white; light colours move towards black.
20080
+ * Selection uses the stronger contrast so selected > hover > normal.
20081
+ */
20082
+ function interactionColorsFromHex(hexColor) {
20083
+ const base = colorHex2RGB(hexColor);
20084
+ const luminance = 0.2126 * base[0] + 0.7152 * base[1] + 0.0722 * base[2];
20085
+ const target = luminance < 0.55 ? 1.0 : 0.0;
20086
+ const mix = (amount) => [
20087
+ base[0] + (target - base[0]) * amount,
20088
+ base[1] + (target - base[1]) * amount,
20089
+ base[2] + (target - base[2]) * amount,
20090
+ ];
20091
+ return {
20092
+ hover: mix(0.45),
20093
+ selected: mix(0.45),
20094
+ };
20095
+ }
19691
20096
  function degToRad(degrees) {
19692
20097
  return (degrees / 180) * Math.PI;
19693
20098
  }
@@ -19734,6 +20139,13 @@ function decDegToDMS(decDeg) {
19734
20139
  d = d * sign;
19735
20140
  return { d, m, s };
19736
20141
  }
20142
+ function raHMSToDeg(hms) {
20143
+ return 15 * (hms.h + hms.m / 60 + hms.s / 3600);
20144
+ }
20145
+ function decDMSToDeg(dms) {
20146
+ const sign = dms.d < 0 || Object.is(dms.d, -0) ? -1 : 1;
20147
+ return sign * (Math.abs(dms.d) + dms.m / 60 + dms.s / 3600);
20148
+ }
19737
20149
 
19738
20150
 
19739
20151
  /***/ },