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
@@ -3630,12 +3630,18 @@ class AstroSphere {
3630
3630
  _activeHiPS = null;
3631
3631
  _activeHiPSLayers = [];
3632
3632
  _activeXYZ2 = null;
3633
+ _earthRasterOverlays = [];
3634
+ _earthRasterOverlaySequence = 0;
3633
3635
  _activeMeshHiPS = null;
3634
3636
  _activeBaseLayer = null;
3637
+ _activeDomain = "astronomy";
3638
+ domainCameraStates = {};
3635
3639
  startup = true;
3636
3640
  fov;
3637
- activeCatalogues = [];
3638
- activeFootprintSets = [];
3641
+ astronomyCatalogues = [];
3642
+ earthPointSets = [];
3643
+ astronomyFootprintSets = [];
3644
+ earthFootprintSets = [];
3639
3645
  activePolylineSets = [];
3640
3646
  activeSensorCones = [];
3641
3647
  activeSatelliteObjects = [];
@@ -3868,9 +3874,7 @@ class AstroSphere {
3868
3874
  return true;
3869
3875
  }
3870
3876
  emitCameraChanged(reason) {
3871
- // avoid dispatch before scene is ready
3872
- if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
3873
- return;
3877
+ // Camera interaction remains meaningful even when no base layer is active.
3874
3878
  if (!this._healpixGrid?.fovObj)
3875
3879
  return;
3876
3880
  const detail = this.getCurrentStatus();
@@ -3935,8 +3939,11 @@ class AstroSphere {
3935
3939
  if (mousePoint && mousePoint.length > 0) {
3936
3940
  this.mouseHelper.update(mousePoint);
3937
3941
  this.updateLastMousePoint();
3938
- for (const cat of this.activeCatalogues) {
3939
- const clickResult = cat.selectPrimarySourceFromClick(this.mouseHelper);
3942
+ for (const cat of this.getActivePointSets()) {
3943
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
3944
+ if (!activeModelMatrix)
3945
+ continue;
3946
+ const clickResult = cat.selectPrimarySourceFromClick(this.mouseHelper, activeModelMatrix, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
3940
3947
  if (!clickResult?.sources.length)
3941
3948
  continue;
3942
3949
  this._webgl.canvas.dispatchEvent(new CustomEvent("source-clicked", {
@@ -3949,7 +3956,7 @@ class AstroSphere {
3949
3956
  composed: true,
3950
3957
  }));
3951
3958
  }
3952
- for (const fset of this.activeFootprintSets) {
3959
+ for (const fset of this.getActiveFootprintSets()) {
3953
3960
  const clickResult = fset.selectPrimaryFootprintFromClick(this.mouseHelper);
3954
3961
  if (!clickResult?.footprints.length)
3955
3962
  continue;
@@ -4046,8 +4053,11 @@ class AstroSphere {
4046
4053
  }
4047
4054
  this.mouseHelper.update(mousePoint);
4048
4055
  this.updateLastMousePoint();
4049
- for (const cat of this.activeCatalogues) {
4050
- const pickResult = cat.getSourcesFromPointer(this.mouseHelper);
4056
+ for (const cat of this.getActivePointSets()) {
4057
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4058
+ if (!activeModelMatrix)
4059
+ continue;
4060
+ const pickResult = cat.getSourcesFromPointer(this.mouseHelper, activeModelMatrix, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4051
4061
  if (!pickResult?.sources.length)
4052
4062
  continue;
4053
4063
  this._webgl.canvas.dispatchEvent(new CustomEvent("source-contextmenu", {
@@ -4062,7 +4072,7 @@ class AstroSphere {
4062
4072
  }));
4063
4073
  break;
4064
4074
  }
4065
- for (const fset of this.activeFootprintSets) {
4075
+ for (const fset of this.getActiveFootprintSets()) {
4066
4076
  const pickResult = fset.getFootprintsFromPointer(this.mouseHelper);
4067
4077
  if (!pickResult?.footprints.length)
4068
4078
  continue;
@@ -4152,19 +4162,22 @@ class AstroSphere {
4152
4162
  return new HiPS_js_1.HiPS(1, [0.0, 0.0, 0.0], 0, 0, hipsDescriptor, this._webgl, this._healpixGrid);
4153
4163
  }
4154
4164
  activateHiPS(hipsDescriptor) {
4165
+ if (this._activeHiPSLayers.length > 0) {
4166
+ throw new Error("Cannot load a HiPS base layer while stacked layers are active.");
4167
+ }
4155
4168
  const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
4156
- for (const hips of this._activeHiPSLayers) {
4157
- tileBuffer.removeHiPS(hips);
4169
+ if (this._activeHiPS) {
4170
+ tileBuffer.removeHiPS(this._activeHiPS);
4158
4171
  }
4159
- this._activeHiPSLayers = [];
4160
4172
  const hips = this.createHiPS(hipsDescriptor);
4161
- this._activeHiPSLayers.push(hips);
4162
4173
  this._activeHiPS = hips;
4174
+ this._activeDomain = "astronomy";
4163
4175
  this._activeBaseLayer = "hips";
4164
4176
  return hips;
4165
4177
  }
4166
4178
  setHiPSOpacity(hips, opacity) {
4167
- if (!this._activeHiPSLayers.includes(hips)) {
4179
+ const isBaseLayer = this._activeHiPSLayers.length === 0 && this._activeHiPS === hips;
4180
+ if (!isBaseLayer && !this._activeHiPSLayers.includes(hips)) {
4168
4181
  throw new Error("HiPS layer is not active in this AstroSphere.");
4169
4182
  }
4170
4183
  hips.setOpacity(opacity);
@@ -4172,6 +4185,13 @@ class AstroSphere {
4172
4185
  addHiPS(hipsDescriptor) {
4173
4186
  const normalizeURL = (url) => String(url).replace(/\/+$/, "");
4174
4187
  const descriptorURL = normalizeURL(hipsDescriptor.url);
4188
+ // Entering stack mode discards the standalone base HiPS. Base mode and
4189
+ // stack mode are intentionally mutually exclusive.
4190
+ if (this._activeHiPSLayers.length === 0 && this._activeHiPS) {
4191
+ const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
4192
+ tileBuffer.removeHiPS(this._activeHiPS);
4193
+ this._activeHiPS = null;
4194
+ }
4175
4195
  const existing = this._activeHiPSLayers.find((hips) => normalizeURL(hips.baseURL) === descriptorURL);
4176
4196
  if (existing) {
4177
4197
  throw new Error(`HiPS already active: ${String(hipsDescriptor.url)}`);
@@ -4179,6 +4199,7 @@ class AstroSphere {
4179
4199
  const hips = this.createHiPS(hipsDescriptor);
4180
4200
  this._activeHiPSLayers.push(hips);
4181
4201
  this._activeHiPS = hips;
4202
+ this._activeDomain = "astronomy";
4182
4203
  this._activeBaseLayer = "hips";
4183
4204
  return hips;
4184
4205
  }
@@ -4203,8 +4224,13 @@ class AstroSphere {
4203
4224
  }
4204
4225
  removeAllHiPS() {
4205
4226
  const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
4206
- for (const hips of this._activeHiPSLayers) {
4207
- tileBuffer.removeHiPS(hips);
4227
+ if (this._activeHiPSLayers.length === 0 && this._activeHiPS) {
4228
+ tileBuffer.removeHiPS(this._activeHiPS);
4229
+ }
4230
+ else {
4231
+ for (const hips of this._activeHiPSLayers) {
4232
+ tileBuffer.removeHiPS(hips);
4233
+ }
4208
4234
  }
4209
4235
  this._activeHiPSLayers = [];
4210
4236
  this._activeHiPS = null;
@@ -4217,39 +4243,169 @@ class AstroSphere {
4217
4243
  this._activeBaseLayer = "xyz";
4218
4244
  }
4219
4245
  activateXYZ2(config) {
4246
+ this._activeDomain = "earth";
4220
4247
  this._activeXYZ2 = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, config, this._webgl, this.gridLabelContainers);
4221
4248
  this._activeBaseLayer = "xyz";
4222
4249
  }
4223
4250
  activateMeshHiPS(descriptor) {
4251
+ this._activeDomain = "mesh";
4224
4252
  this._activeMeshHiPS = new MeshHiPS_js_1.MeshHiPS(descriptor.meshRadius, [0.0, 0.0, 0.0], 0, 0, descriptor, this._webgl, this._healpixGrid);
4225
4253
  this._activeBaseLayer = "meships";
4226
4254
  }
4255
+ setMeshHiPSColor(color) {
4256
+ this._activeMeshHiPS?.setColor(color);
4257
+ }
4258
+ setMeshHiPSWireframe(wireframe) {
4259
+ this._activeMeshHiPS?.setWireframe(wireframe);
4260
+ }
4227
4261
  activateWMTS(config) {
4262
+ this._activeDomain = "earth";
4228
4263
  const adapter = new WMTSAdapter_js_1.WMTSAdapter(config);
4229
4264
  const xyzConfig = adapter.toXYZLayerConfig();
4230
4265
  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);
4231
4266
  this._activeBaseLayer = "xyz";
4232
4267
  }
4233
- // Catalogue section
4268
+ addXYZRasterOverlay(config) {
4269
+ const map = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, config, this._webgl, this.gridLabelContainers);
4270
+ return this.addEarthRasterOverlay(config.name, "xyz", map);
4271
+ }
4272
+ addWMTSRasterOverlay(config) {
4273
+ const adapter = new WMTSAdapter_js_1.WMTSAdapter(config);
4274
+ const xyzConfig = adapter.toXYZLayerConfig();
4275
+ const name = config.layer ? `WMTS ${config.layer}` : "WMTS Earth Raster Overlay";
4276
+ 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);
4277
+ return this.addEarthRasterOverlay(name, "wmts", map);
4278
+ }
4279
+ getEarthRasterOverlays() {
4280
+ return this._earthRasterOverlays.map(({ map: _map, ...overlay }) => ({ ...overlay }));
4281
+ }
4282
+ setEarthRasterOverlayOpacity(id, opacity) {
4283
+ const overlay = this._earthRasterOverlays.find((entry) => entry.id === id);
4284
+ if (!overlay)
4285
+ return;
4286
+ overlay.opacity = Math.min(1, Math.max(0, opacity));
4287
+ overlay.map.setOpacity(overlay.opacity);
4288
+ }
4289
+ setEarthRasterOverlayVisible(id, visible) {
4290
+ const overlay = this._earthRasterOverlays.find((entry) => entry.id === id);
4291
+ if (overlay)
4292
+ overlay.visible = visible;
4293
+ }
4294
+ removeEarthRasterOverlay(id) {
4295
+ this._earthRasterOverlays = this._earthRasterOverlays.filter((entry) => entry.id !== id);
4296
+ }
4297
+ removeAllEarthRasterOverlays() {
4298
+ this._earthRasterOverlays = [];
4299
+ }
4300
+ addEarthRasterOverlay(name, sourceType, map) {
4301
+ const overlay = {
4302
+ id: `earth-raster-${++this._earthRasterOverlaySequence}`,
4303
+ name,
4304
+ sourceType,
4305
+ visible: true,
4306
+ opacity: 0.65,
4307
+ map,
4308
+ };
4309
+ map.setOpacity(overlay.opacity);
4310
+ this._earthRasterOverlays.push(overlay);
4311
+ const { map: _map, ...info } = overlay;
4312
+ return { ...info };
4313
+ }
4314
+ setActiveDomain(domain) {
4315
+ if (domain !== this._activeDomain) {
4316
+ this.clearGridLabelsForDomain(this._activeDomain);
4317
+ this.domainCameraStates[this._activeDomain] = this._camera.getViewState();
4318
+ const targetCameraState = this.domainCameraStates[domain];
4319
+ if (targetCameraState) {
4320
+ this._camera.restoreViewState(targetCameraState);
4321
+ }
4322
+ this.inertiaX = 0;
4323
+ this.inertiaY = 0;
4324
+ this.zoomInertia = 0;
4325
+ this._cameraStatusChanged = true;
4326
+ }
4327
+ this._activeDomain = domain;
4328
+ if (domain === "astronomy") {
4329
+ this._activeBaseLayer = this._activeHiPS ? "hips" : null;
4330
+ }
4331
+ else if (domain === "earth") {
4332
+ this._activeBaseLayer = this._activeXYZ2 ? "xyz" : null;
4333
+ }
4334
+ else {
4335
+ this._activeBaseLayer = this._activeMeshHiPS ? "meships" : null;
4336
+ }
4337
+ // A hover from the previous vertical must not leak into the new one.
4338
+ this.lastHoveredSource = null;
4339
+ this.lastHoveredCatalogue = null;
4340
+ }
4341
+ clearGridLabelsForDomain(domain) {
4342
+ if (domain === "astronomy") {
4343
+ this._healpixGrid?.clearLabels();
4344
+ this._equatorialGrid?.clearLabels();
4345
+ return;
4346
+ }
4347
+ if (domain === "earth") {
4348
+ this._activeXYZ2?.clearLonLatGridLabels?.();
4349
+ }
4350
+ }
4351
+ get activeDomain() {
4352
+ return this._activeDomain;
4353
+ }
4354
+ getActivePointSets() {
4355
+ if (this._activeDomain === "astronomy")
4356
+ return this.astronomyCatalogues;
4357
+ if (this._activeDomain === "earth")
4358
+ return this.earthPointSets;
4359
+ return [];
4360
+ }
4361
+ getActiveFootprintSets() {
4362
+ if (this._activeDomain === "astronomy")
4363
+ return this.astronomyFootprintSets;
4364
+ if (this._activeDomain === "earth")
4365
+ return this.earthFootprintSets;
4366
+ return [];
4367
+ }
4368
+ // Astronomy catalogue ownership
4234
4369
  async showCatalogue(cat) {
4235
- // console.log(cat)
4236
- if (cat)
4237
- this.activeCatalogues.push(cat);
4370
+ if (cat && !this.astronomyCatalogues.includes(cat)) {
4371
+ this.astronomyCatalogues.push(cat);
4372
+ }
4238
4373
  return cat;
4239
4374
  }
4240
4375
  deleteCatalogue(catalogue) {
4241
- this.activeCatalogues = this.activeCatalogues.filter((c) => c !== catalogue);
4376
+ this.astronomyCatalogues = this.astronomyCatalogues.filter((c) => c !== catalogue);
4242
4377
  }
4243
- // End Catalogue section
4244
- // Footprint section
4378
+ // Earth point-set ownership. TerraPointSetGL still extends CatalogueGL in
4379
+ // 3.12, but it no longer shares the Astronomy lifecycle collection.
4380
+ async showTerraPointSet(pointSet) {
4381
+ if (pointSet && !this.earthPointSets.includes(pointSet)) {
4382
+ this.earthPointSets.push(pointSet);
4383
+ }
4384
+ return pointSet;
4385
+ }
4386
+ deleteTerraPointSet(pointSet) {
4387
+ this.earthPointSets = this.earthPointSets.filter((set) => set !== pointSet);
4388
+ }
4389
+ // Astronomy footprint ownership
4245
4390
  async showFootprintSet(fset) {
4246
- // console.log(fset)
4247
- if (fset)
4248
- this.activeFootprintSets.push(fset);
4391
+ if (fset && !this.astronomyFootprintSets.includes(fset)) {
4392
+ this.astronomyFootprintSets.push(fset);
4393
+ }
4249
4394
  return fset;
4250
4395
  }
4251
4396
  deleteFootprintSet(footprintSet) {
4252
- this.activeFootprintSets = this.activeFootprintSets.filter((fst) => fst !== footprintSet);
4397
+ this.astronomyFootprintSets = this.astronomyFootprintSets.filter((fst) => fst !== footprintSet);
4398
+ }
4399
+ // Earth footprint ownership. TerraFootprintSetGL still reuses the common
4400
+ // FootprintSetGL rendering implementation, but has an independent lifecycle.
4401
+ async showTerraFootprintSet(footprintSet) {
4402
+ if (footprintSet && !this.earthFootprintSets.includes(footprintSet)) {
4403
+ this.earthFootprintSets.push(footprintSet);
4404
+ }
4405
+ return footprintSet;
4406
+ }
4407
+ deleteTerraFootprintSet(footprintSet) {
4408
+ this.earthFootprintSets = this.earthFootprintSets.filter((fst) => fst !== footprintSet);
4253
4409
  }
4254
4410
  async showPolylineSet(polylineSet) {
4255
4411
  if (polylineSet)
@@ -4279,8 +4435,8 @@ class AstroSphere {
4279
4435
  satelliteObject.dispose();
4280
4436
  }
4281
4437
  getHoveredFootprints() {
4282
- let footprintsHovered = [];
4283
- this.activeFootprintSets.forEach((fset) => {
4438
+ const footprintsHovered = [];
4439
+ this.getActiveFootprintSets().forEach((fset) => {
4284
4440
  footprintsHovered.push(fset.hoveredFootprints);
4285
4441
  });
4286
4442
  return footprintsHovered;
@@ -4512,8 +4668,6 @@ class AstroSphere {
4512
4668
  return;
4513
4669
  if (!this._webgl)
4514
4670
  return;
4515
- if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
4516
- return;
4517
4671
  if (!this._healpixGrid || Object.keys(this._healpixGrid).length === 0)
4518
4672
  return;
4519
4673
  if (this._healpixGrid.fovObj === undefined)
@@ -4625,8 +4779,10 @@ class AstroSphere {
4625
4779
  this._webgl.enable(this._webgl.CULL_FACE);
4626
4780
  this._webgl.cullFace(Global_js_1.default.insideSphere ? this._webgl.FRONT : this._webgl.BACK);
4627
4781
  this._webgl.blendFunc(this._webgl.SRC_ALPHA, this._webgl.ONE_MINUS_SRC_ALPHA);
4628
- if (this._activeBaseLayer === "hips" && this._activeHiPSLayers.length > 0) {
4629
- const maxHiPSOrder = Math.max(...this._activeHiPSLayers.map((hips) => hips.maxOrder));
4782
+ if (this._activeBaseLayer === "hips" && this._activeHiPS) {
4783
+ const maxHiPSOrder = this._activeHiPSLayers.length > 0
4784
+ ? Math.max(...this._activeHiPSLayers.map((hips) => hips.maxOrder))
4785
+ : this._activeHiPS.maxOrder;
4630
4786
  const visibleOrder = Math.min(this._healpixGrid.visibleorder, maxHiPSOrder);
4631
4787
  this._healpixGrid.visibleTilesManager.computeVisiblePixels(visibleOrder, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
4632
4788
  }
@@ -4661,12 +4817,19 @@ class AstroSphere {
4661
4817
  }
4662
4818
  if (this._activeBaseLayer === "xyz") {
4663
4819
  this._activeXYZ2?.draw(skyEntityDrawInput);
4820
+ for (const overlay of this._earthRasterOverlays) {
4821
+ if (overlay.visible) {
4822
+ overlay.map.draw(skyEntityDrawInput, true);
4823
+ }
4824
+ }
4664
4825
  }
4665
4826
  if (this._activeBaseLayer === "meships") {
4666
4827
  this._activeMeshHiPS?.draw(skyEntityDrawInput);
4667
4828
  }
4668
- this._healpixGrid.draw(skyEntityDrawInput);
4669
- this._equatorialGrid.draw(skyEntityDrawInput);
4829
+ if (this._activeDomain === "astronomy") {
4830
+ this._healpixGrid.draw(skyEntityDrawInput);
4831
+ this._equatorialGrid.draw(skyEntityDrawInput);
4832
+ }
4670
4833
  this._webgl.enable(this._webgl.DEPTH_TEST);
4671
4834
  this._webgl.disable(this._webgl.CULL_FACE);
4672
4835
  if (this.startup) {
@@ -4685,52 +4848,53 @@ class AstroSphere {
4685
4848
  decDMS,
4686
4849
  });
4687
4850
  }
4688
- this.activeCatalogues.forEach((cat) => {
4689
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4690
- this._activeXYZ2?.getModelMatrix() ??
4691
- this._activeMeshHiPS?.getModelMatrix();
4851
+ this.getActivePointSets().forEach((cat) => {
4852
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4692
4853
  if (activeModelMatrix) {
4693
4854
  cat.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4694
4855
  }
4695
4856
  });
4696
4857
  this.emitHoveredSourceIfChanged();
4697
- this.activeFootprintSets.forEach((fst) => {
4698
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4699
- this._activeXYZ2?.getModelMatrix() ??
4700
- this._activeMeshHiPS?.getModelMatrix();
4858
+ this.getActiveFootprintSets().forEach((fst) => {
4859
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4701
4860
  if (activeModelMatrix) {
4702
4861
  fst.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4703
4862
  }
4704
4863
  });
4705
- this.activePolylineSets.forEach((polylineSet) => {
4706
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4707
- this._activeXYZ2?.getModelMatrix() ??
4708
- this._activeMeshHiPS?.getModelMatrix();
4709
- if (activeModelMatrix) {
4710
- polylineSet.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4711
- }
4712
- });
4713
- this.activeSensorCones.forEach((sensorCone) => {
4714
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4715
- this._activeXYZ2?.getModelMatrix() ??
4716
- this._activeMeshHiPS?.getModelMatrix();
4717
- if (activeModelMatrix) {
4718
- sensorCone.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4719
- }
4720
- });
4721
- this.activeSatelliteObjects.forEach((satelliteObject) => {
4722
- const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
4723
- this._activeXYZ2?.getModelMatrix() ??
4724
- this._activeMeshHiPS?.getModelMatrix();
4725
- if (activeModelMatrix) {
4726
- satelliteObject.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4727
- }
4728
- });
4864
+ if (this._activeDomain === "earth") {
4865
+ this.activePolylineSets.forEach((polylineSet) => {
4866
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4867
+ if (activeModelMatrix) {
4868
+ polylineSet.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
4869
+ }
4870
+ });
4871
+ this.activeSensorCones.forEach((sensorCone) => {
4872
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4873
+ if (activeModelMatrix) {
4874
+ sensorCone.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4875
+ }
4876
+ });
4877
+ this.activeSatelliteObjects.forEach((satelliteObject) => {
4878
+ const activeModelMatrix = this.getActiveDomainModelMatrix();
4879
+ if (activeModelMatrix) {
4880
+ satelliteObject.draw(this._perspectiveMatrixManager.pMatrix, this._camera.getCameraMatrix(), activeModelMatrix);
4881
+ }
4882
+ });
4883
+ }
4884
+ }
4885
+ getActiveDomainModelMatrix() {
4886
+ if (this._activeDomain === "astronomy") {
4887
+ return (this._activeHiPS?.getModelMatrix() ?? this._healpixGrid.getModelMatrix());
4888
+ }
4889
+ if (this._activeDomain === "earth") {
4890
+ return (this._activeXYZ2?.getModelMatrix() ?? this._healpixGrid.getModelMatrix());
4891
+ }
4892
+ return (this._activeMeshHiPS?.getModelMatrix() ?? this._healpixGrid.getModelMatrix());
4729
4893
  }
4730
4894
  emitHoveredSourceIfChanged() {
4731
4895
  let nextHoveredSource = null;
4732
4896
  let nextHoveredCatalogue = null;
4733
- for (const cat of this.activeCatalogues) {
4897
+ for (const cat of this.getActivePointSets()) {
4734
4898
  const hovered = cat.getPrimaryHoveredSource();
4735
4899
  if (!hovered)
4736
4900
  continue;
@@ -4858,25 +5022,25 @@ class AstroViewer {
4858
5022
  return new TerraPointSetGL_js_1.TerraPointSetGL(pointSetName, pointSetDescription, providerUrl, metadataManager, this.webgl, this.astroSphere.healpixGrid.visibleTilesManager);
4859
5023
  }
4860
5024
  showTerraPointSet(pointSet) {
4861
- this.astroSphere.showCatalogue(pointSet);
5025
+ this.astroSphere.showTerraPointSet(pointSet);
4862
5026
  }
4863
5027
  hideTerraPointSet(pointSet, isVisible) {
4864
5028
  pointSet.setIsVisible(isVisible);
4865
5029
  }
4866
5030
  deleteTerraPointSet(pointSet) {
4867
- this.astroSphere.deleteCatalogue(pointSet);
5031
+ this.astroSphere.deleteTerraPointSet(pointSet);
4868
5032
  }
4869
5033
  createTerraFootprintSet(footprintSetName, footprintSetDescription, providerUrl, metadataManager) {
4870
5034
  return new TerraFootprintSetGL_js_1.TerraFootprintSetGL(footprintSetName, footprintSetDescription, providerUrl, metadataManager, this.webgl);
4871
5035
  }
4872
5036
  showTerraFootprintSet(footprintSet) {
4873
- this.astroSphere.showFootprintSet(footprintSet);
5037
+ this.astroSphere.showTerraFootprintSet(footprintSet);
4874
5038
  }
4875
5039
  hideTerraFootprintSet(footprintSet, isVisible) {
4876
5040
  footprintSet.setIsVisible(isVisible);
4877
5041
  }
4878
5042
  deleteTerraFootprintSet(footprintSet) {
4879
- this.astroSphere.deleteFootprintSet(footprintSet);
5043
+ this.astroSphere.deleteTerraFootprintSet(footprintSet);
4880
5044
  }
4881
5045
  createTerraPolylineSet(polylineSetName, polylineSetDescription, providerUrl, metadataManager) {
4882
5046
  return new TerraPolylineSetGL_js_1.TerraPolylineSetGL(polylineSetName, polylineSetDescription, providerUrl, metadataManager, this.webgl);
@@ -4929,6 +5093,12 @@ class AstroViewer {
4929
5093
  getDefaultHiPSURL() {
4930
5094
  return Config_js_1.bootSetup.defaultHipsUrl;
4931
5095
  }
5096
+ setActiveDomain(domain) {
5097
+ this.astroSphere.setActiveDomain(domain);
5098
+ }
5099
+ getActiveDomain() {
5100
+ return this.astroSphere.activeDomain;
5101
+ }
4932
5102
  activateHiPS(hipsDescriptor) {
4933
5103
  this.astroSphere.activateHiPS(hipsDescriptor);
4934
5104
  }
@@ -4942,9 +5112,37 @@ class AstroViewer {
4942
5112
  activateWMTS(config) {
4943
5113
  this.astroSphere.activateWMTS(config);
4944
5114
  }
5115
+ addXYZRasterOverlay(config) {
5116
+ 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);
5117
+ return this.astroSphere.addXYZRasterOverlay(descriptor);
5118
+ }
5119
+ addWMTSRasterOverlay(config) {
5120
+ return this.astroSphere.addWMTSRasterOverlay(config);
5121
+ }
5122
+ getEarthRasterOverlays() {
5123
+ return this.astroSphere.getEarthRasterOverlays();
5124
+ }
5125
+ setEarthRasterOverlayOpacity(id, opacity) {
5126
+ this.astroSphere.setEarthRasterOverlayOpacity(id, opacity);
5127
+ }
5128
+ setEarthRasterOverlayVisible(id, visible) {
5129
+ this.astroSphere.setEarthRasterOverlayVisible(id, visible);
5130
+ }
5131
+ removeEarthRasterOverlay(id) {
5132
+ this.astroSphere.removeEarthRasterOverlay(id);
5133
+ }
5134
+ removeAllEarthRasterOverlays() {
5135
+ this.astroSphere.removeAllEarthRasterOverlays();
5136
+ }
4945
5137
  activateMeshHiPS(config) {
4946
5138
  this.astroSphere.activateMeshHiPS(new MeshHiPSDescriptor_js_1.MeshHiPSDescriptor(config));
4947
5139
  }
5140
+ setMeshHiPSColor(color) {
5141
+ this.astroSphere.setMeshHiPSColor(color);
5142
+ }
5143
+ setMeshHiPSWireframe(wireframe) {
5144
+ this.astroSphere.setMeshHiPSWireframe(wireframe);
5145
+ }
4948
5146
  setXYZMaxConcurrentRequests(value) {
4949
5147
  XYZTileRequestScheduler_js_1.xyzTileRequestScheduler.setMaxConcurrent(value);
4950
5148
  }
@@ -5747,6 +5945,22 @@ class Camera {
5747
5945
  }
5748
5946
  return [inv[12], inv[13], inv[14]];
5749
5947
  }
5948
+ getViewState() {
5949
+ return {
5950
+ position: [this.cam_pos[0], this.cam_pos[1], this.cam_pos[2]],
5951
+ viewMatrix: gl_matrix_1.mat4.clone(this.vMatrix),
5952
+ translationMatrix: gl_matrix_1.mat4.clone(this.T),
5953
+ rotationMatrix: gl_matrix_1.mat4.clone(this.R),
5954
+ };
5955
+ }
5956
+ restoreViewState(state) {
5957
+ this.cancelFlyTo();
5958
+ this.cam_pos = gl_matrix_1.vec3.fromValues(...state.position);
5959
+ this.vMatrix = gl_matrix_1.mat4.clone(state.viewMatrix);
5960
+ this.T = gl_matrix_1.mat4.clone(state.translationMatrix);
5961
+ this.R = gl_matrix_1.mat4.clone(state.rotationMatrix);
5962
+ this.move = gl_matrix_1.vec3.create();
5963
+ }
5750
5964
  setCameraMatrix(viewMatrix) {
5751
5965
  this.vMatrix = viewMatrix;
5752
5966
  }
@@ -5961,7 +6175,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5961
6175
  return (mod && mod.__esModule) ? mod : { "default": mod };
5962
6176
  };
5963
6177
  Object.defineProperty(exports, "__esModule", ({ value: true }));
5964
- 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;
6178
+ 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;
5965
6179
  var AstroViewer_js_1 = __webpack_require__(772);
5966
6180
  Object.defineProperty(exports, "AstroViewer", ({ enumerable: true, get: function () { return AstroViewer_js_1.AstroViewer; } }));
5967
6181
  var HiPSDescriptor_js_1 = __webpack_require__(5087);
@@ -6002,6 +6216,9 @@ Object.defineProperty(exports, "SphericalOpts", ({ enumerable: true, get: functi
6002
6216
  Object.defineProperty(exports, "AstroOpts", ({ enumerable: true, get: function () { return Point_js_1.AstroOpts; } }));
6003
6217
  Object.defineProperty(exports, "PointInitOpts", ({ enumerable: true, get: function () { return Point_js_1.PointInitOpts; } }));
6004
6218
  Object.defineProperty(exports, "CartesianOpts", ({ enumerable: true, get: function () { return Point_js_1.CartesianOpts; } }));
6219
+ var Utils_js_1 = __webpack_require__(7930);
6220
+ Object.defineProperty(exports, "raHMSToDeg", ({ enumerable: true, get: function () { return Utils_js_1.raHMSToDeg; } }));
6221
+ Object.defineProperty(exports, "decDMSToDeg", ({ enumerable: true, get: function () { return Utils_js_1.decDMSToDeg; } }));
6005
6222
  var FoVUtils_js_1 = __webpack_require__(8083);
6006
6223
  Object.defineProperty(exports, "FoVUtils", ({ enumerable: true, get: function () { return FoVUtils_js_1.FoVUtils; } }));
6007
6224
  var CoordsType_js_1 = __webpack_require__(8145);
@@ -8002,7 +8219,7 @@ class Source {
8002
8219
  this._point = in_point;
8003
8220
  this._details = in_details;
8004
8221
  this._shapesize = 16.0;
8005
- this._brightnessFactor = -99;
8222
+ this._brightnessFactor = 3.0;
8006
8223
  this.computeHealpixPixel();
8007
8224
  }
8008
8225
  getDetailByindex(index) {
@@ -8289,12 +8506,13 @@ const Utils_js_1 = __webpack_require__(7930);
8289
8506
  const CatalogueShaderProgram_js_1 = __webpack_require__(3559);
8290
8507
  const MetadataManager_js_1 = __webpack_require__(5403);
8291
8508
  const gl_matrix_1 = __webpack_require__(3890);
8509
+ const healpix_1 = __webpack_require__(4851);
8292
8510
  const Global_js_1 = __importDefault(__webpack_require__(4382));
8293
8511
  class CatalogueGL {
8294
8512
  _kind = "CatalogueGL";
8295
8513
  static ELEM_SIZE = 6;
8296
8514
  static BYTES_X_ELEM = new Float32Array().BYTES_PER_ELEMENT;
8297
- static STANDARD_SHAPE_SIZE = 10.0;
8515
+ static STANDARD_SHAPE_SIZE = 16.0;
8298
8516
  static STANDARD_SHAPE_HUE = 3.0;
8299
8517
  _ready;
8300
8518
  _name;
@@ -8537,7 +8755,7 @@ class CatalogueGL {
8537
8755
  getColumnIndex(columnsmeta, columnName) {
8538
8756
  if (!columnName)
8539
8757
  return -1;
8540
- return columnsmeta.find((column) => column.name === columnName)?.index ?? -1;
8758
+ return (columnsmeta.find((column) => column.name === columnName)?.index ?? -1);
8541
8759
  }
8542
8760
  readCell(row, columnsmeta, columnName) {
8543
8761
  const idx = this.getColumnIndex(columnsmeta, columnName);
@@ -8550,7 +8768,9 @@ class CatalogueGL {
8550
8768
  const src = String(rawSrc ?? "").trim();
8551
8769
  if (!src)
8552
8770
  return undefined;
8553
- const rawKind = String(this.readCell(row, columnsmeta, mediaColumns.type) ?? "sprite").trim().toLowerCase();
8771
+ const rawKind = String(this.readCell(row, columnsmeta, mediaColumns.type) ?? "sprite")
8772
+ .trim()
8773
+ .toLowerCase();
8554
8774
  const kind = rawKind === "model"
8555
8775
  ? "model"
8556
8776
  : rawKind === "image"
@@ -8570,7 +8790,9 @@ class CatalogueGL {
8570
8790
  src,
8571
8791
  scale: Number.isFinite(scale) && scale > 0 ? scale : undefined,
8572
8792
  rotationDeg: Number.isFinite(rotationDeg) ? rotationDeg : undefined,
8573
- opacity: Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : undefined,
8793
+ opacity: Number.isFinite(opacity)
8794
+ ? Math.max(0, Math.min(1, opacity))
8795
+ : undefined,
8574
8796
  };
8575
8797
  }
8576
8798
  clearSources() {
@@ -8861,33 +9083,46 @@ class CatalogueGL {
8861
9083
  this._webgl.bufferData(this._webgl.ARRAY_BUFFER, this.vertexCataloguePosition, this._webgl.STATIC_DRAW);
8862
9084
  this._bufferInitialised = true;
8863
9085
  }
8864
- getSelectionRadius() {
8865
- const order = this._visibleTilesManager.getVisibleOrder();
8866
- switch (order) {
8867
- case 0:
8868
- case 1:
8869
- case 2:
8870
- // return 0.005;
8871
- return 0.01;
8872
- case 3:
8873
- // return 0.001;
8874
- case 4:
8875
- // return 0.0009;
8876
- case 5:
8877
- // return 0.0005;
8878
- return 0.005;
8879
- case 6:
8880
- // return 0.0001;
8881
- case 7:
8882
- // return 0.00009;
8883
- case 8:
8884
- // return 0.00005;
8885
- return 0.001;
8886
- case 9:
8887
- return 0.0005;
8888
- default:
8889
- return 0.0001;
9086
+ static MIN_HIT_RADIUS_PX = 6;
9087
+ static HIT_PADDING_PX = 3;
9088
+ static CANDIDATE_RADIUS_PX = 16;
9089
+ getCanvas() {
9090
+ return this._webgl.canvas;
9091
+ }
9092
+ getHitRadiusPx(source) {
9093
+ const markerSize = source.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
9094
+ return Math.max(CatalogueGL.MIN_HIT_RADIUS_PX, markerSize / 2 + CatalogueGL.HIT_PADDING_PX);
9095
+ }
9096
+ getCandidateSearchRadiusRad(pMatrix) {
9097
+ const canvas = this._webgl.canvas;
9098
+ const width = Math.max(1, canvas.clientWidth);
9099
+ const height = Math.max(1, canvas.clientHeight);
9100
+ // pMatrix[0] and pMatrix[5] are the perspective scale factors for X/Y.
9101
+ // Convert a small screen-space radius to a conservative angular radius.
9102
+ const fovXRad = 2 * Math.atan(1 / Math.abs(pMatrix[0]));
9103
+ const fovYRad = 2 * Math.atan(1 / Math.abs(pMatrix[5]));
9104
+ const radPerPixel = Math.max(fovXRad / width, fovYRad / height);
9105
+ return CatalogueGL.CANDIDATE_RADIUS_PX * radPerPixel;
9106
+ }
9107
+ projectPointToScreen(point, mvp, width, height) {
9108
+ const projected = gl_matrix_1.vec4.fromValues(point.x, point.y, point.z, 1);
9109
+ gl_matrix_1.vec4.transformMat4(projected, projected, mvp);
9110
+ if (projected[3] <= 0)
9111
+ return null;
9112
+ const ndcX = projected[0] / projected[3];
9113
+ const ndcY = projected[1] / projected[3];
9114
+ return [(ndcX * 0.5 + 0.5) * width, (1 - (ndcY * 0.5 + 0.5)) * height];
9115
+ }
9116
+ clearSelection() {
9117
+ for (const idx of this.selectedIndexes) {
9118
+ const base = idx * CatalogueGL.ELEM_SIZE;
9119
+ if (base + 4 >= this.vertexCataloguePosition.length)
9120
+ continue;
9121
+ this.vertexCataloguePosition[base + 3] = 0.0;
9122
+ this.vertexCataloguePosition[base + 4] =
9123
+ this._sources[idx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8890
9124
  }
9125
+ this.selectedIndexes = [];
8891
9126
  }
8892
9127
  setSelectedIndexes(selectedIndex) {
8893
9128
  selectedIndex.forEach((idx) => {
@@ -8914,8 +9149,8 @@ class CatalogueGL {
8914
9149
  * Run click-picking and update selection with the nearest candidate in current pixel.
8915
9150
  * Returns the selected source or null if no source was hit.
8916
9151
  */
8917
- getSourcesFromPointer(in_mouseHelper) {
8918
- const pickedIndexes = this.checkClicking(in_mouseHelper);
9152
+ getSourcesFromPointer(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9153
+ const pickedIndexes = this.checkClicking(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
8919
9154
  if (!pickedIndexes.length) {
8920
9155
  return {
8921
9156
  sources: [],
@@ -8934,8 +9169,8 @@ class CatalogueGL {
8934
9169
  * Run click-picking and update selection with the nearest candidate in current pixel.
8935
9170
  * Returns the selected source or null if no source was hit.
8936
9171
  */
8937
- selectPrimarySourceFromClick(in_mouseHelper) {
8938
- const picked = this.getSourcesFromPointer(in_mouseHelper);
9172
+ selectPrimarySourceFromClick(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9173
+ const picked = this.getSourcesFromPointer(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
8939
9174
  const clickedIndexes = picked?.pickedIndexes ?? [];
8940
9175
  // if (!clickedIndexes.length) {
8941
9176
  // this.setSelectedIndexes([]);
@@ -8971,42 +9206,65 @@ class CatalogueGL {
8971
9206
  const idx = this.hoveredIndexes[0];
8972
9207
  return this._sources[idx] ?? null;
8973
9208
  }
8974
- findNearestSourceIndex(in_mouseHelper) {
8975
- if (in_mouseHelper.x == null ||
8976
- in_mouseHelper.y == null ||
8977
- in_mouseHelper.z == null) {
9209
+ findNearestSourceIndex(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9210
+ if (in_mouseHelper.xyz == null)
8978
9211
  return null;
9212
+ const healpix = Global_js_1.default.getHealpix(Global_js_1.default.selectionOrder);
9213
+ const mouseVec = new healpix_1.Vec3(...in_mouseHelper.xyz);
9214
+ const mousePointing = new healpix_1.Pointing(mouseVec, false);
9215
+ const searchRadiusRad = this.getCandidateSearchRadiusRad(pMatrix);
9216
+ const rangeSet = healpix.queryDiscInclusive(mousePointing, searchRadiusRad, 4);
9217
+ const pixels = rangeSet.r;
9218
+ const candidateIndexes = new Set();
9219
+ for (const pixel of pixels) {
9220
+ const indexes = this._healpixDensityMap.get(pixel);
9221
+ if (!indexes)
9222
+ continue;
9223
+ indexes.forEach((idx) => candidateIndexes.add(idx));
8979
9224
  }
8980
- const mousePix = in_mouseHelper.computeNpix();
8981
- if (mousePix == null)
9225
+ if (!candidateIndexes.size)
9226
+ return null;
9227
+ const canvas = this._webgl.canvas;
9228
+ const width = canvas.clientWidth;
9229
+ const height = canvas.clientHeight;
9230
+ if (!width || !height)
8982
9231
  return null;
8983
- const candidates = this._healpixDensityMap.get(mousePix);
8984
- if (!candidates?.length)
9232
+ const modelView = gl_matrix_1.mat4.create();
9233
+ const mvp = gl_matrix_1.mat4.create();
9234
+ gl_matrix_1.mat4.multiply(modelView, vMatrix, in_mMatrix);
9235
+ gl_matrix_1.mat4.multiply(mvp, pMatrix, modelView);
9236
+ const mousePoint = new Point_js_1.Point({
9237
+ x: in_mouseHelper.xyz[0],
9238
+ y: in_mouseHelper.xyz[1],
9239
+ z: in_mouseHelper.xyz[2],
9240
+ }, CoordsType_js_1.CoordsType.CARTESIAN);
9241
+ const mouseScreen = this.projectPointToScreen(mousePoint, mvp, width, height);
9242
+ if (!mouseScreen)
8985
9243
  return null;
8986
- const selR = this.getSelectionRadius();
8987
9244
  let nearestIndex = null;
8988
- let nearestDistance = Number.POSITIVE_INFINITY;
8989
- for (const sourceIdx of candidates) {
9245
+ let nearestDistancePx = Number.POSITIVE_INFINITY;
9246
+ for (const sourceIdx of candidateIndexes) {
8990
9247
  const source = this._sources[sourceIdx];
8991
9248
  if (!source)
8992
9249
  continue;
8993
- const dx = source.point.x - in_mouseHelper.x;
8994
- const dy = source.point.y - in_mouseHelper.y;
8995
- const dz = source.point.z - in_mouseHelper.z;
8996
- const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
8997
- if (dist <= selR && dist < nearestDistance) {
8998
- nearestDistance = dist;
9250
+ const sourceScreen = this.projectPointToScreen(source.point, mvp, width, height);
9251
+ if (!sourceScreen)
9252
+ continue;
9253
+ const distancePx = Math.hypot(sourceScreen[0] - mouseScreen[0], sourceScreen[1] - mouseScreen[1]);
9254
+ if (distancePx <= this.getHitRadiusPx(source) &&
9255
+ distancePx < nearestDistancePx) {
9256
+ nearestDistancePx = distancePx;
8999
9257
  nearestIndex = sourceIdx;
9000
9258
  }
9001
9259
  }
9002
9260
  return nearestIndex;
9003
9261
  }
9004
- checkClicking(in_mouseHelper) {
9005
- const nearestIndex = this.findNearestSourceIndex(in_mouseHelper);
9262
+ checkClicking(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9263
+ const nearestIndex = this.findNearestSourceIndex(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
9006
9264
  return nearestIndex == null ? [] : [nearestIndex];
9007
9265
  }
9008
- checkHovering(in_mouseHelper) {
9009
- const nearestIndex = this.findNearestSourceIndex(in_mouseHelper);
9266
+ checkHovering(in_mouseHelper, in_mMatrix, vMatrix, pMatrix) {
9267
+ const nearestIndex = this.findNearestSourceIndex(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
9010
9268
  return nearestIndex == null ? [] : [nearestIndex];
9011
9269
  }
9012
9270
  /**
@@ -9042,6 +9300,13 @@ class CatalogueGL {
9042
9300
  if (this._catalogueShaderProgram.locations.color) {
9043
9301
  this._webgl.uniform4f(this._catalogueShaderProgram.locations.color, rgb[0], rgb[1], rgb[2], 1.0);
9044
9302
  }
9303
+ const interactionColors = (0, Utils_js_1.interactionColorsFromHex)(this._shapeColor);
9304
+ if (this._catalogueShaderProgram.locations.hoverColor) {
9305
+ this._webgl.uniform4f(this._catalogueShaderProgram.locations.hoverColor, ...interactionColors.hover, 1.0);
9306
+ }
9307
+ if (this._catalogueShaderProgram.locations.selectedColor) {
9308
+ this._webgl.uniform4f(this._catalogueShaderProgram.locations.selectedColor, ...interactionColors.selected, 1.0);
9309
+ }
9045
9310
  // selected flags
9046
9311
  for (let s = 0; s < this.selectedIndexes.length; s++) {
9047
9312
  const idx = this.selectedIndexes[s];
@@ -9052,7 +9317,8 @@ class CatalogueGL {
9052
9317
  // clear old hovered
9053
9318
  for (let k = 0; k < this.hoveredIndexes.length; k++) {
9054
9319
  const base = this.hoveredIndexes[k] * CatalogueGL.ELEM_SIZE;
9055
- // if (this.vertexCataloguePosition[base + 3] == 2.0) continue; // selected, skip hover
9320
+ if (this.selectedIndexes.includes(this.hoveredIndexes[k]))
9321
+ continue;
9056
9322
  this.vertexCataloguePosition[base + 3] = 0.0; // not hovered
9057
9323
  this.vertexCataloguePosition[base + 4] =
9058
9324
  this._sources[this.hoveredIndexes[k]].shapeSize; // size
@@ -9066,7 +9332,7 @@ class CatalogueGL {
9066
9332
  // this.vertexCataloguePosition[base + 3] = 0.0; // not hovered
9067
9333
  // this.vertexCataloguePosition[base + 4] = this._sources[this.hoveredIndexes[k]].shapeSize; // size
9068
9334
  // }
9069
- this.hoveredIndexes = this.checkHovering(in_mouseHelper);
9335
+ this.hoveredIndexes = this.checkHovering(in_mouseHelper, in_mMatrix, vMatrix, pMatrix);
9070
9336
  // // new hovered
9071
9337
  // for (let i = 0; i < this.hoveredIndexes.length; i++) {
9072
9338
  // const idx = this.hoveredIndexes[i];
@@ -9080,7 +9346,8 @@ class CatalogueGL {
9080
9346
  for (let i = 0; i < this.hoveredIndexes.length; i++) {
9081
9347
  const idx = this.hoveredIndexes[i];
9082
9348
  const base = idx * CatalogueGL.ELEM_SIZE;
9083
- // if (this.vertexCataloguePosition[base + 3] == 2.0) continue; // selected, skip hover
9349
+ if (this.selectedIndexes.includes(idx))
9350
+ continue;
9084
9351
  this.vertexCataloguePosition[base + 3] = 1.0; // hovered
9085
9352
  this.vertexCataloguePosition[base + 4] = this._sources[idx].shapeSize; // size
9086
9353
  }
@@ -9484,6 +9751,7 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9484
9751
  _latLonGrid;
9485
9752
  _colorMapIdx = 0;
9486
9753
  _colorMap = ColorMaps_js_1.ColorMaps['native'];
9754
+ _opacity = 1;
9487
9755
  constructor(radius, position, xrad, yrad, descriptor, webgl, gridLabelContainers) {
9488
9756
  super(radius, position, xrad, yrad, descriptor.name, webgl, false);
9489
9757
  this._descriptor = descriptor;
@@ -9498,6 +9766,10 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9498
9766
  const fov = 180;
9499
9767
  this._zoom = XYZFoVHelper_js_1.xyzFovHelper.getZoom(fov);
9500
9768
  }
9769
+ setOpacity(opacity) {
9770
+ this._opacity = Math.min(1, Math.max(0, opacity));
9771
+ this._xyzShaderProgram.setOpacity(this._opacity);
9772
+ }
9501
9773
  changeColorMap(colorMap) {
9502
9774
  this._colorMap = colorMap;
9503
9775
  switch (colorMap.name) {
@@ -9545,6 +9817,9 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9545
9817
  initShaders() {
9546
9818
  this._xyzShaderProgram.enableProgram();
9547
9819
  }
9820
+ clearLonLatGridLabels() {
9821
+ this._latLonGrid.clearLabels();
9822
+ }
9548
9823
  isLonLatGridVisible() {
9549
9824
  return this._latLonGrid.isVisible();
9550
9825
  }
@@ -9559,7 +9834,7 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9559
9834
  // this._zoom = this.resolveVisibleZoom(fov)
9560
9835
  this._zoom = XYZFoVHelper_js_1.xyzFovHelper.getZoom(fov);
9561
9836
  }
9562
- draw(input) {
9837
+ draw(input, asOverlay = false) {
9563
9838
  const vMatrix = input.camera.getCameraMatrix();
9564
9839
  if (!vMatrix)
9565
9840
  return;
@@ -9569,6 +9844,18 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9569
9844
  this.refresh(input);
9570
9845
  const mMatrix = this.getModelMatrix();
9571
9846
  this._xyzShaderProgram.setRuntimeColorMap(this._colorMap);
9847
+ this._xyzShaderProgram.setOpacity(this._opacity);
9848
+ const depthTestWasEnabled = this._webgl.isEnabled(this._webgl.DEPTH_TEST);
9849
+ const blendWasEnabled = this._webgl.isEnabled(this._webgl.BLEND);
9850
+ const blendSrcRgb = this._webgl.getParameter(this._webgl.BLEND_SRC_RGB);
9851
+ const blendDstRgb = this._webgl.getParameter(this._webgl.BLEND_DST_RGB);
9852
+ const blendSrcAlpha = this._webgl.getParameter(this._webgl.BLEND_SRC_ALPHA);
9853
+ const blendDstAlpha = this._webgl.getParameter(this._webgl.BLEND_DST_ALPHA);
9854
+ if (asOverlay) {
9855
+ this._webgl.disable(this._webgl.DEPTH_TEST);
9856
+ this._webgl.enable(this._webgl.BLEND);
9857
+ this._webgl.blendFunc(this._webgl.SRC_ALPHA, this._webgl.ONE_MINUS_SRC_ALPHA);
9858
+ }
9572
9859
  const tileSelection = this._visibleTilesManager.computeVisibleTiles(this._zoom, this, this._webgl, input.camera, input.pMatrix);
9573
9860
  const visibleTiles = tileSelection.visibleTiles;
9574
9861
  const ancestorsMap = tileSelection.ancestorsMap;
@@ -9586,7 +9873,20 @@ class XYZMap extends AbstractSkyEntity_js_1.AbstractSkyEntity {
9586
9873
  const ancestorTile = this.findBestAvailableAncestor(tile.coord);
9587
9874
  ancestorTile?.draw(tileSelection.currentZoom, [tile.coord], ancestorsMap, pMatrix, vMatrix, mMatrix, this._colorMapIdx);
9588
9875
  }
9589
- this._latLonGrid.draw(input);
9876
+ if (asOverlay) {
9877
+ if (depthTestWasEnabled)
9878
+ this._webgl.enable(this._webgl.DEPTH_TEST);
9879
+ else
9880
+ this._webgl.disable(this._webgl.DEPTH_TEST);
9881
+ this._webgl.blendFuncSeparate(blendSrcRgb, blendDstRgb, blendSrcAlpha, blendDstAlpha);
9882
+ if (blendWasEnabled)
9883
+ this._webgl.enable(this._webgl.BLEND);
9884
+ else
9885
+ this._webgl.disable(this._webgl.BLEND);
9886
+ }
9887
+ else {
9888
+ this._latLonGrid.draw(input);
9889
+ }
9590
9890
  }
9591
9891
  createTile(coord) {
9592
9892
  return new XYZAnchestorTile_js_1.XYZAnchestorTile(coord, this.resolveTileUrl(coord), this._webgl, this._xyzShaderProgram, this._meshBuilder, this._descriptor.segmentsPerSide);
@@ -10872,6 +11172,10 @@ class FootprintSetGL {
10872
11172
  }
10873
11173
  return clickedIndexes;
10874
11174
  }
11175
+ clearSelection() {
11176
+ this.selectedIndexes = [];
11177
+ this.refreshSelectedFootprints();
11178
+ }
10875
11179
  setSelectedIndexes(selectedIndex) {
10876
11180
  selectedIndex.forEach((idx) => {
10877
11181
  if (idx < 0 || idx >= this.footprintPolygons.length)
@@ -11173,9 +11477,10 @@ class FootprintSetGL {
11173
11477
  if (in_mouseHelper != null && in_mouseHelper.xyz != this.oldMouseCoords) {
11174
11478
  this.checkSelection(in_mouseHelper);
11175
11479
  }
11480
+ const interactionColors = (0, Utils_js_1.interactionColorsFromHex)(this._shapeColor);
11176
11481
  if (this._hoveredFootprints.length > 0) {
11177
11482
  // TODO POINT_SIZE doesn't have any effect on line thickness!! it only applies to points
11178
- const rgb = (0, Utils_js_1.colorHex2RGB)("#00FF00");
11483
+ const rgb = interactionColors.hover;
11179
11484
  const alpha = 1.0;
11180
11485
  this._webgl.uniform4f(this._footprintShaderProgram.locations.color, rgb[0], rgb[1], rgb[2], alpha);
11181
11486
  this._webgl.uniform1f(this._footprintShaderProgram.locations.pointSize, 14.0); // <--- POINT_SIZE in LINE_LOOP is not applicable
@@ -11190,7 +11495,7 @@ class FootprintSetGL {
11190
11495
  this._webgl.drawElements(this._webgl.LINE_LOOP, this.hoveredVertexPosition.length / 3 + this.nHoveredPrimitiveFlags, this._webgl.UNSIGNED_INT, 0);
11191
11496
  }
11192
11497
  if (this._selectedFootprints.length > 0) {
11193
- const rgb = (0, Utils_js_1.colorHex2RGB)("#ECB462");
11498
+ const rgb = interactionColors.selected;
11194
11499
  const alpha = 1.0;
11195
11500
  this._webgl.uniform4f(this._footprintShaderProgram.locations.color, rgb[0], rgb[1], rgb[2], alpha);
11196
11501
  this._webgl.uniform1f(this._footprintShaderProgram.locations.pointSize, 14.0); // <--- POINT_SIZE in LINE_LOOP is not applicable
@@ -11203,6 +11508,11 @@ class FootprintSetGL {
11203
11508
  this._webgl.bufferData(this._webgl.ELEMENT_ARRAY_BUFFER, this.selectedElementIndexes, this._webgl.STATIC_DRAW);
11204
11509
  // this._gl.drawElements (this._gl.LINE_LOOP, this._selectedVertexPosition.length / 3 + this._nSlectedPrimitiveFlags,this._gl.UNSIGNED_SHORT, 0);
11205
11510
  this._webgl.drawElements(this._webgl.LINE_LOOP, this.selectedVertexPosition.length / 3 + this.nSlectedPrimitiveFlags, this._webgl.UNSIGNED_INT, 0);
11511
+ // Keep selection visually distinct from hover without relying on
11512
+ // non-portable line widths. Reuse the selected geometry as small
11513
+ // vertex markers; POINT_SIZE is supported for POINTS in WebGL2.
11514
+ this._webgl.uniform1f(this._footprintShaderProgram.locations.pointSize, 4.0);
11515
+ this._webgl.drawElements(this._webgl.POINTS, this.selectedVertexPosition.length / 3 + this.nSlectedPrimitiveFlags, this._webgl.UNSIGNED_INT, 0);
11206
11516
  }
11207
11517
  this._webgl.bindBuffer(this._webgl.ARRAY_BUFFER, this.vertexCataloguePositionBuffer);
11208
11518
  this._webgl.vertexAttribPointer(this._footprintShaderProgram.locations.position, FootprintSetGL.ELEM_SIZE, this._webgl.FLOAT, false, FootprintSetGL.BYTES_X_ELEM * FootprintSetGL.ELEM_SIZE, 0);
@@ -11435,6 +11745,9 @@ class EquatorialGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
11435
11745
  gl.uniform4f(uColor, rgb[0], rgb[1], rgb[2], 1.0);
11436
11746
  }
11437
11747
  }
11748
+ clearLabels() {
11749
+ this.gridText.resetDivSets();
11750
+ }
11438
11751
  isVisible() {
11439
11752
  return this.showGrid;
11440
11753
  }
@@ -12029,6 +12342,9 @@ class HealpixGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12029
12342
  this.gridText.resetDivSets();
12030
12343
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
12031
12344
  }
12345
+ clearLabels() {
12346
+ this.gridText.resetDivSets();
12347
+ }
12032
12348
  get visibleorder() {
12033
12349
  return this._visibleorder;
12034
12350
  }
@@ -12262,6 +12578,9 @@ class LatLonGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12262
12578
  gl.uniform4f(uColor, rgb[0], rgb[1], rgb[2], 1.0);
12263
12579
  }
12264
12580
  }
12581
+ clearLabels() {
12582
+ this.gridText.resetDivSets();
12583
+ }
12265
12584
  draw(input) {
12266
12585
  if (!this._showGrid) {
12267
12586
  this.gridText.resetDivSets();
@@ -14919,6 +15238,8 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14919
15238
  _currentOrder;
14920
15239
  _visibleTiles = [];
14921
15240
  _coverageTiles = [];
15241
+ _color;
15242
+ _wireframe;
14922
15243
  constructor(radius, position, xrad, yrad, _descriptor, webgl, _healpixGrid) {
14923
15244
  super(radius, position, xrad, yrad, _descriptor.name, webgl, false);
14924
15245
  this._descriptor = _descriptor;
@@ -14927,6 +15248,8 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14927
15248
  this._shaderProgram = new MeshHiPSShaderProgram_js_1.MeshHiPSShaderProgram(webgl);
14928
15249
  this._shaderProgram.enableProgram();
14929
15250
  this._currentOrder = _descriptor.selectedOrder;
15251
+ this._color = [..._descriptor.color];
15252
+ this._wireframe = _descriptor.wireframe;
14930
15253
  }
14931
15254
  get currentOrder() {
14932
15255
  return this._currentOrder;
@@ -14949,6 +15272,12 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14949
15272
  getProperty(key) {
14950
15273
  return this._descriptor.getProperty(key);
14951
15274
  }
15275
+ setColor(color) {
15276
+ this._color = [...color];
15277
+ }
15278
+ setWireframe(wireframe) {
15279
+ this._wireframe = wireframe;
15280
+ }
14952
15281
  refreshOrder(fovDeg) {
14953
15282
  if (this._descriptor.fixedOrder) {
14954
15283
  this._currentOrder = this._descriptor.selectedOrder;
@@ -14988,7 +15317,7 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14988
15317
  for (const coord of byOrder.get(order) ?? []) {
14989
15318
  this._tiles
14990
15319
  .get(this.tileKey(coord))
14991
- ?.draw(pMatrix, vMatrix, mMatrix, this._descriptor.color, this._descriptor.wireframe);
15320
+ ?.draw(pMatrix, vMatrix, mMatrix, this._color, this._wireframe);
14992
15321
  }
14993
15322
  }
14994
15323
  if (wasCullFace)
@@ -16769,6 +17098,7 @@ exports.TerraFootprintSetGL = TerraFootprintSetGL;
16769
17098
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16770
17099
  exports.TerraPointSetGL = void 0;
16771
17100
  const CatalogueGL_js_1 = __webpack_require__(1232);
17101
+ const gl_matrix_1 = __webpack_require__(3890);
16772
17102
  const MetadataManager_js_1 = __webpack_require__(5403);
16773
17103
  const Point_js_1 = __webpack_require__(6553);
16774
17104
  const CoordsType_js_1 = __webpack_require__(8145);
@@ -16803,8 +17133,45 @@ class TerraPointSetGL extends CatalogueGL_js_1.CatalogueGL {
16803
17133
  this._ready = true;
16804
17134
  this._bufferInitialised = false;
16805
17135
  }
17136
+ findNearestSourceIndex(inMouseHelper, inMatrix, viewMatrix, projectionMatrix) {
17137
+ if (inMouseHelper.xyz == null)
17138
+ return null;
17139
+ const canvas = this.getCanvas();
17140
+ const width = canvas.clientWidth;
17141
+ const height = canvas.clientHeight;
17142
+ if (!width || !height)
17143
+ return null;
17144
+ const modelView = gl_matrix_1.mat4.create();
17145
+ const mvp = gl_matrix_1.mat4.create();
17146
+ gl_matrix_1.mat4.multiply(modelView, viewMatrix, inMatrix);
17147
+ gl_matrix_1.mat4.multiply(mvp, projectionMatrix, modelView);
17148
+ const mousePoint = new Point_js_1.Point({
17149
+ x: inMouseHelper.xyz[0],
17150
+ y: inMouseHelper.xyz[1],
17151
+ z: inMouseHelper.xyz[2],
17152
+ }, CoordsType_js_1.CoordsType.CARTESIAN);
17153
+ const mouseScreen = this.projectPointToScreen(mousePoint, mvp, width, height);
17154
+ if (!mouseScreen)
17155
+ return null;
17156
+ let nearestIndex = null;
17157
+ let nearestDistancePx = Number.POSITIVE_INFINITY;
17158
+ for (let index = 0; index < this._sources.length; index += 1) {
17159
+ const source = this._sources[index];
17160
+ if (!source)
17161
+ continue;
17162
+ const sourceScreen = this.projectPointToScreen(source.point, mvp, width, height);
17163
+ if (!sourceScreen)
17164
+ continue;
17165
+ const distancePx = Math.hypot(sourceScreen[0] - mouseScreen[0], sourceScreen[1] - mouseScreen[1]);
17166
+ if (distancePx <= this.getHitRadiusPx(source) &&
17167
+ distancePx < nearestDistancePx) {
17168
+ nearestDistancePx = distancePx;
17169
+ nearestIndex = index;
17170
+ }
17171
+ }
17172
+ return nearestIndex;
17173
+ }
16806
17174
  draw(inMatrix, inMouseHelper, viewMatrix, projectionMatrix) {
16807
- this._oldMouseCoords = inMouseHelper?.xyz ?? null;
16808
17175
  super.draw(inMatrix, inMouseHelper, viewMatrix, projectionMatrix);
16809
17176
  }
16810
17177
  }
@@ -17034,6 +17401,8 @@ class CatalogueShaderProgram {
17034
17401
  this._webgl = webgl;
17035
17402
  this.gl_uniforms = {
17036
17403
  vertex_color: 'u_fragcolor',
17404
+ hover_color: 'u_hovercolor',
17405
+ selected_color: 'u_selectedcolor',
17037
17406
  m_perspective: 'uPMatrix',
17038
17407
  m_model_view: 'uMVMatrix'
17039
17408
  };
@@ -17047,6 +17416,8 @@ class CatalogueShaderProgram {
17047
17416
  pMatrix: null,
17048
17417
  mvMatrix: null,
17049
17418
  color: null,
17419
+ hoverColor: null,
17420
+ selectedColor: null,
17050
17421
  position: -1,
17051
17422
  hovered: -1,
17052
17423
  pointSize: -1,
@@ -17096,6 +17467,8 @@ class CatalogueShaderProgram {
17096
17467
  this.locations.pointSize = gl.getAttribLocation(this.shaderProgram, this.gl_attributes.point_size);
17097
17468
  this.locations.brightness = gl.getAttribLocation(this.shaderProgram, this.gl_attributes.point_hue);
17098
17469
  this.locations.color = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.vertex_color);
17470
+ this.locations.hoverColor = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.hover_color);
17471
+ this.locations.selectedColor = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.selected_color);
17099
17472
  }
17100
17473
  enableShaders(pMatrix, modelMatrix, viewMatrix) {
17101
17474
  // const gl = global.gl as GL
@@ -17781,6 +18154,8 @@ class ShaderManager {
17781
18154
  in float v_brightness;
17782
18155
 
17783
18156
  uniform vec4 u_fragcolor;
18157
+ uniform vec4 u_hovercolor;
18158
+ uniform vec4 u_selectedcolor;
17784
18159
 
17785
18160
  out vec4 fragColor;
17786
18161
 
@@ -17837,11 +18212,12 @@ class ShaderManager {
17837
18212
  #endif
17838
18213
 
17839
18214
  if (v_selected == 1.0){
17840
- // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * (alpha);
17841
- fragColor = vec4(1.0, 0.0, 0.0, 1.0) * (alpha);
18215
+ fragColor = u_hovercolor * alpha;
17842
18216
  } else if (v_selected == 2.0){
17843
- // gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0) * (alpha);
17844
- fragColor = vec4(1.0, 1.0, 0.0, 1.0) * (alpha);
18217
+ // Persistent selection: keep the dataset colour as an outer ring
18218
+ // and use the hover colour for the fill. This remains visible for
18219
+ // both light and dark user-selected base colours.
18220
+ fragColor = (r > 0.72 ? u_fragcolor : u_hovercolor) * alpha;
17845
18221
  }else{
17846
18222
  if (r < 0.4) {
17847
18223
  discard;
@@ -18248,6 +18624,7 @@ class XYZShaderProgram {
18248
18624
  _shaderProgram;
18249
18625
  _colorMapBlockIndex = null;
18250
18626
  _colorMapBuffer = null;
18627
+ _opacity = 1;
18251
18628
  _runtimeColorMap;
18252
18629
  _colorMapVariableInfo = {
18253
18630
  r_palette: { index: 0, offset: 0 },
@@ -18262,6 +18639,7 @@ class XYZShaderProgram {
18262
18639
  vMatrix: null,
18263
18640
  sampler: null,
18264
18641
  colorMapIdx: null,
18642
+ opacity: null,
18265
18643
  vertexPositionAttribute: -1,
18266
18644
  textureCoordAttribute: -1,
18267
18645
  };
@@ -18282,6 +18660,9 @@ class XYZShaderProgram {
18282
18660
  enableProgram() {
18283
18661
  this._webgl.useProgram(this.shaderProgram);
18284
18662
  }
18663
+ setOpacity(opacity) {
18664
+ this._opacity = Math.min(1, Math.max(0, opacity));
18665
+ }
18285
18666
  setRuntimeColorMap(colorMap) {
18286
18667
  this._runtimeColorMap = colorMap;
18287
18668
  }
@@ -18294,6 +18675,7 @@ class XYZShaderProgram {
18294
18675
  this.locations.vMatrix = gl.getUniformLocation(program, 'uVMatrix');
18295
18676
  this.locations.sampler = gl.getUniformLocation(program, 'uSampler');
18296
18677
  this.locations.colorMapIdx = gl.getUniformLocation(program, 'cmapIdx');
18678
+ this.locations.opacity = gl.getUniformLocation(program, 'uOpacity');
18297
18679
  this.locations.vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition');
18298
18680
  this.locations.textureCoordAttribute = gl.getAttribLocation(program, 'aTextureCoord');
18299
18681
  gl.uniformMatrix4fv(this.locations.pMatrix, false, pMatrix);
@@ -18301,6 +18683,7 @@ class XYZShaderProgram {
18301
18683
  gl.uniformMatrix4fv(this.locations.mMatrix, false, mMatrix);
18302
18684
  gl.uniform1i(this.locations.sampler, 0);
18303
18685
  gl.uniform1i(this.locations.colorMapIdx, colorMapIdx);
18686
+ gl.uniform1f(this.locations.opacity, this._opacity);
18304
18687
  if (colorMapIdx >= 2) {
18305
18688
  this.uploadColorMap(colorMapIdx);
18306
18689
  }
@@ -18323,6 +18706,7 @@ class XYZShaderProgram {
18323
18706
  in vec2 vTextureCoord;
18324
18707
  uniform sampler2D uSampler;
18325
18708
  uniform int cmapIdx;
18709
+ uniform float uOpacity;
18326
18710
 
18327
18711
  layout (std140) uniform colormap {
18328
18712
  float r_palette[256];
@@ -18337,7 +18721,7 @@ class XYZShaderProgram {
18337
18721
 
18338
18722
  if (cmapIdx == 1) {
18339
18723
  float gray = 0.21 * color.r + 0.71 * color.g + 0.07 * color.b;
18340
- outColor = vec4(vec3(gray), color.a);
18724
+ outColor = vec4(vec3(gray), color.a * uOpacity);
18341
18725
  return;
18342
18726
  }
18343
18727
 
@@ -18350,12 +18734,12 @@ class XYZShaderProgram {
18350
18734
  r_palette[rIndex] / 256.0,
18351
18735
  g_palette[gIndex] / 256.0,
18352
18736
  b_palette[bIndex] / 256.0,
18353
- color.a
18737
+ color.a * uOpacity
18354
18738
  );
18355
18739
  return;
18356
18740
  }
18357
18741
 
18358
- outColor = color;
18742
+ outColor = vec4(color.rgb, color.a * uOpacity);
18359
18743
  }`);
18360
18744
  gl.attachShader(this._shaderProgram, vertexShader);
18361
18745
  gl.attachShader(this._shaderProgram, fragmentShader);
@@ -19557,7 +19941,6 @@ exports["default"] = STCSParser;
19557
19941
  /***/ 7930
19558
19942
  (__unused_webpack_module, exports, __webpack_require__) {
19559
19943
 
19560
- var __webpack_unused_export__;
19561
19944
 
19562
19945
  /*
19563
19946
  * AstroViewer
@@ -19569,9 +19952,10 @@ var __webpack_unused_export__;
19569
19952
  *
19570
19953
  * See LICENSE.md, LICENSE-AGPL.md, and LICENSE-COMMERCIAL.md for details.
19571
19954
  */
19572
- __webpack_unused_export__ = ({ value: true });
19955
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
19573
19956
  exports.cartesianToSpherical = cartesianToSpherical;
19574
19957
  exports.colorHex2RGB = colorHex2RGB;
19958
+ exports.interactionColorsFromHex = interactionColorsFromHex;
19575
19959
  exports.degToRad = degToRad;
19576
19960
  exports.radToDeg = radToDeg;
19577
19961
  exports.sphericalToAstroDeg = sphericalToAstroDeg;
@@ -19579,6 +19963,8 @@ exports.sphericalToCartesian = sphericalToCartesian;
19579
19963
  exports.astroDegToSpherical = astroDegToSpherical;
19580
19964
  exports.raDegToHMS = raDegToHMS;
19581
19965
  exports.decDegToDMS = decDegToDMS;
19966
+ exports.raHMSToDeg = raHMSToDeg;
19967
+ exports.decDMSToDeg = decDMSToDeg;
19582
19968
  /**
19583
19969
  * @author Fabrizio Giordano (Fab)
19584
19970
  */
@@ -19609,6 +19995,25 @@ function colorHex2RGB(hexColor) {
19609
19995
  const rgb3 = (dec3 / 255).toFixed(2);
19610
19996
  return [parseFloat(rgb1), parseFloat(rgb2), parseFloat(rgb3)];
19611
19997
  }
19998
+ /**
19999
+ * Derive interaction colours from the object's normal colour.
20000
+ * Dark colours move towards white; light colours move towards black.
20001
+ * Selection uses the stronger contrast so selected > hover > normal.
20002
+ */
20003
+ function interactionColorsFromHex(hexColor) {
20004
+ const base = colorHex2RGB(hexColor);
20005
+ const luminance = 0.2126 * base[0] + 0.7152 * base[1] + 0.0722 * base[2];
20006
+ const target = luminance < 0.55 ? 1.0 : 0.0;
20007
+ const mix = (amount) => [
20008
+ base[0] + (target - base[0]) * amount,
20009
+ base[1] + (target - base[1]) * amount,
20010
+ base[2] + (target - base[2]) * amount,
20011
+ ];
20012
+ return {
20013
+ hover: mix(0.45),
20014
+ selected: mix(0.45),
20015
+ };
20016
+ }
19612
20017
  function degToRad(degrees) {
19613
20018
  return (degrees / 180) * Math.PI;
19614
20019
  }
@@ -19655,6 +20060,13 @@ function decDegToDMS(decDeg) {
19655
20060
  d = d * sign;
19656
20061
  return { d, m, s };
19657
20062
  }
20063
+ function raHMSToDeg(hms) {
20064
+ return 15 * (hms.h + hms.m / 60 + hms.s / 3600);
20065
+ }
20066
+ function decDMSToDeg(dms) {
20067
+ const sign = dms.d < 0 || Object.is(dms.d, -0) ? -1 : 1;
20068
+ return sign * (Math.abs(dms.d) + dms.m / 60 + dms.s / 3600);
20069
+ }
19658
20070
 
19659
20071
 
19660
20072
  /***/ },