astro-viewer 3.8.0 → 3.10.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 (84) hide show
  1. package/README.md +325 -222
  2. package/dist/astroviewer.cjs +469 -198
  3. package/dist/astroviewer.cjs.map +1 -1
  4. package/dist/astroviewer.js +469 -198
  5. package/dist/astroviewer.js.map +1 -1
  6. package/dist/astroviewer.min.js +1 -1
  7. package/dist/astroviewer.min.js.map +1 -1
  8. package/lib-esm/AstroSphere.d.ts +4 -0
  9. package/lib-esm/AstroSphere.d.ts.map +1 -1
  10. package/lib-esm/AstroSphere.js +15 -0
  11. package/lib-esm/AstroSphere.js.map +1 -1
  12. package/lib-esm/AstroViewer.d.ts +4 -0
  13. package/lib-esm/AstroViewer.d.ts.map +1 -1
  14. package/lib-esm/AstroViewer.js +12 -3
  15. package/lib-esm/AstroViewer.js.map +1 -1
  16. package/lib-esm/Global.d.ts +3 -3
  17. package/lib-esm/Global.d.ts.map +1 -1
  18. package/lib-esm/Global.js +38 -16
  19. package/lib-esm/Global.js.map +1 -1
  20. package/lib-esm/index.d.ts +1 -0
  21. package/lib-esm/index.d.ts.map +1 -1
  22. package/lib-esm/index.js +0 -1
  23. package/lib-esm/index.js.map +1 -1
  24. package/lib-esm/model/Source.d.ts.map +1 -1
  25. package/lib-esm/model/Source.js +2 -1
  26. package/lib-esm/model/Source.js.map +1 -1
  27. package/lib-esm/model/catalogues/CatalogueGL.d.ts +8 -7
  28. package/lib-esm/model/catalogues/CatalogueGL.d.ts.map +1 -1
  29. package/lib-esm/model/catalogues/CatalogueGL.js +63 -86
  30. package/lib-esm/model/catalogues/CatalogueGL.js.map +1 -1
  31. package/lib-esm/model/footprints/FootprintSetGL.d.ts +1 -3
  32. package/lib-esm/model/footprints/FootprintSetGL.d.ts.map +1 -1
  33. package/lib-esm/model/footprints/FootprintSetGL.js +1 -3
  34. package/lib-esm/model/footprints/FootprintSetGL.js.map +1 -1
  35. package/lib-esm/model/grid/HealpixGrid.d.ts.map +1 -1
  36. package/lib-esm/model/grid/HealpixGrid.js +7 -1
  37. package/lib-esm/model/grid/HealpixGrid.js.map +1 -1
  38. package/lib-esm/model/hips/AllSky.d.ts.map +1 -1
  39. package/lib-esm/model/hips/AllSky.js +3 -25
  40. package/lib-esm/model/hips/AllSky.js.map +1 -1
  41. package/lib-esm/model/hips/AncestorTile.d.ts.map +1 -1
  42. package/lib-esm/model/hips/AncestorTile.js +3 -25
  43. package/lib-esm/model/hips/AncestorTile.js.map +1 -1
  44. package/lib-esm/model/hips/FitsTileLoader.d.ts +4 -0
  45. package/lib-esm/model/hips/FitsTileLoader.d.ts.map +1 -1
  46. package/lib-esm/model/hips/FitsTileLoader.js +39 -1
  47. package/lib-esm/model/hips/FitsTileLoader.js.map +1 -1
  48. package/lib-esm/model/hips/HiPS.d.ts +24 -0
  49. package/lib-esm/model/hips/HiPS.d.ts.map +1 -1
  50. package/lib-esm/model/hips/HiPS.js +153 -0
  51. package/lib-esm/model/hips/HiPS.js.map +1 -1
  52. package/lib-esm/model/hips/Tile.d.ts.map +1 -1
  53. package/lib-esm/model/hips/Tile.js +3 -25
  54. package/lib-esm/model/hips/Tile.js.map +1 -1
  55. package/lib-esm/model/hips/VisibleTilesManager.d.ts +6 -3
  56. package/lib-esm/model/hips/VisibleTilesManager.d.ts.map +1 -1
  57. package/lib-esm/model/hips/VisibleTilesManager.js.map +1 -1
  58. package/lib-esm/model/meships/MeshHiPS.d.ts +4 -4
  59. package/lib-esm/model/meships/MeshHiPS.d.ts.map +1 -1
  60. package/lib-esm/model/meships/MeshHiPS.js +28 -12
  61. package/lib-esm/model/meships/MeshHiPS.js.map +1 -1
  62. package/lib-esm/model/terra/TerraFootprintSetGL.d.ts +2 -0
  63. package/lib-esm/model/terra/TerraFootprintSetGL.d.ts.map +1 -1
  64. package/lib-esm/model/terra/TerraFootprintSetGL.js +19 -0
  65. package/lib-esm/model/terra/TerraFootprintSetGL.js.map +1 -1
  66. package/lib-esm/model/terra/TerraPointSetGL.d.ts +4 -0
  67. package/lib-esm/model/terra/TerraPointSetGL.d.ts.map +1 -1
  68. package/lib-esm/model/terra/TerraPointSetGL.js +36 -0
  69. package/lib-esm/model/terra/TerraPointSetGL.js.map +1 -1
  70. package/lib-esm/model/terra/TerraPolylineSetGL.d.ts +1 -3
  71. package/lib-esm/model/terra/TerraPolylineSetGL.d.ts.map +1 -1
  72. package/lib-esm/model/terra/TerraPolylineSetGL.js +1 -3
  73. package/lib-esm/model/terra/TerraPolylineSetGL.js.map +1 -1
  74. package/lib-esm/shader/HiPSShaderProgram.d.ts +5 -1
  75. package/lib-esm/shader/HiPSShaderProgram.d.ts.map +1 -1
  76. package/lib-esm/shader/HiPSShaderProgram.js +15 -1
  77. package/lib-esm/shader/HiPSShaderProgram.js.map +1 -1
  78. package/lib-esm/shader/ShaderManager.d.ts.map +1 -1
  79. package/lib-esm/shader/ShaderManager.js +39 -7
  80. package/lib-esm/shader/ShaderManager.js.map +1 -1
  81. package/lib-esm/utils/MouseHelper.d.ts.map +1 -1
  82. package/lib-esm/utils/MouseHelper.js +2 -1
  83. package/lib-esm/utils/MouseHelper.js.map +1 -1
  84. package/package.json +1 -1
@@ -4130,6 +4130,21 @@ class AstroSphere {
4130
4130
  }
4131
4131
  this._activeHiPS.changeFormat(format);
4132
4132
  }
4133
+ setHiPSFITSScaleFunction(scaleFunction, scaleParam) {
4134
+ if (!this._activeHiPS) {
4135
+ throw new Error("No active HiPS.");
4136
+ }
4137
+ this._activeHiPS.setFITSScaleFunction(scaleFunction, scaleParam);
4138
+ }
4139
+ getActiveHiPSFITSStretch() {
4140
+ return this._activeHiPS?.fitsStretch ?? null;
4141
+ }
4142
+ setHiPSFITSRangeMode(rangeMode) {
4143
+ if (!this._activeHiPS) {
4144
+ throw new Error("No active HiPS.");
4145
+ }
4146
+ this._activeHiPS.setFITSRangeMode(rangeMode);
4147
+ }
4133
4148
  createHiPS(hipsDescriptor) {
4134
4149
  return new HiPS_js_1.HiPS(1, [0.0, 0.0, 0.0], 0, 0, hipsDescriptor, this._webgl, this._healpixGrid);
4135
4150
  }
@@ -4811,7 +4826,7 @@ class AstroViewer {
4811
4826
  }
4812
4827
  //FOOTPRINT
4813
4828
  createFootprintSet(footprintSetName, footprintSetDescription, providerUrl, metadataManager) {
4814
- return new FootprintSetGL_js_1.FootprintSetGL(footprintSetName, footprintSetDescription, providerUrl, metadataManager, this.webgl, this.astroSphere.healpixGrid.visibleTilesManager);
4829
+ return new FootprintSetGL_js_1.FootprintSetGL(footprintSetName, footprintSetDescription, providerUrl, metadataManager, this.webgl);
4815
4830
  }
4816
4831
  showFootprintSet(footprintSet) {
4817
4832
  this.astroSphere.showFootprintSet(footprintSet);
@@ -4836,7 +4851,7 @@ class AstroViewer {
4836
4851
  this.astroSphere.deleteCatalogue(pointSet);
4837
4852
  }
4838
4853
  createTerraFootprintSet(footprintSetName, footprintSetDescription, providerUrl, metadataManager) {
4839
- return new TerraFootprintSetGL_js_1.TerraFootprintSetGL(footprintSetName, footprintSetDescription, providerUrl, metadataManager, this.webgl, this.astroSphere.healpixGrid.visibleTilesManager);
4854
+ return new TerraFootprintSetGL_js_1.TerraFootprintSetGL(footprintSetName, footprintSetDescription, providerUrl, metadataManager, this.webgl);
4840
4855
  }
4841
4856
  showTerraFootprintSet(footprintSet) {
4842
4857
  this.astroSphere.showFootprintSet(footprintSet);
@@ -4848,7 +4863,7 @@ class AstroViewer {
4848
4863
  this.astroSphere.deleteFootprintSet(footprintSet);
4849
4864
  }
4850
4865
  createTerraPolylineSet(polylineSetName, polylineSetDescription, providerUrl, metadataManager) {
4851
- return new TerraPolylineSetGL_js_1.TerraPolylineSetGL(polylineSetName, polylineSetDescription, providerUrl, metadataManager, this.webgl, this.astroSphere.healpixGrid.visibleTilesManager);
4866
+ return new TerraPolylineSetGL_js_1.TerraPolylineSetGL(polylineSetName, polylineSetDescription, providerUrl, metadataManager, this.webgl);
4852
4867
  }
4853
4868
  showTerraPolylineSet(polylineSet) {
4854
4869
  this.astroSphere.showPolylineSet(polylineSet);
@@ -5001,6 +5016,15 @@ class AstroViewer {
5001
5016
  changeHiPSFormat(format) {
5002
5017
  this.astroSphere.changeHiPSFormat(format);
5003
5018
  }
5019
+ setHiPSFITSScaleFunction(scaleFunction, scaleParam) {
5020
+ this.astroSphere.setHiPSFITSScaleFunction(scaleFunction, scaleParam);
5021
+ }
5022
+ getActiveHiPSFITSStretch() {
5023
+ return this.astroSphere.getActiveHiPSFITSStretch();
5024
+ }
5025
+ setHiPSFITSRangeMode(rangeMode) {
5026
+ this.astroSphere.setHiPSFITSRangeMode(rangeMode);
5027
+ }
5004
5028
  getActiveHiPSFormats() {
5005
5029
  return this.astroSphere.activeHiPS?.availableFormats ?? [];
5006
5030
  }
@@ -5738,7 +5762,7 @@ class Global {
5738
5762
  // private _gl: GL | null;
5739
5763
  _healpix;
5740
5764
  // --- config/state flags ---
5741
- _selectionnside;
5765
+ // private _selectionnside: number;
5742
5766
  // private _healpix4footprints: boolean;
5743
5767
  _useCORSProxy;
5744
5768
  _corsProxyUrl;
@@ -5746,6 +5770,7 @@ class Global {
5746
5770
  _debug;
5747
5771
  _insideSphere;
5748
5772
  _version;
5773
+ _selectionOrder;
5749
5774
  constructor() {
5750
5775
  this._useCORSProxy = Config_js_1.bootSetup.useCORSProxy;
5751
5776
  this._corsProxyUrl = Config_js_1.bootSetup.corsProxyUrl;
@@ -5754,18 +5779,34 @@ class Global {
5754
5779
  this._insideSphere = Config_js_1.bootSetup.insideView;
5755
5780
  this._version = Config_js_1.bootSetup.version;
5756
5781
  this._healpix = {};
5757
- this._selectionnside = 32;
5782
+ // this._selectionnside = 32;
5783
+ this._selectionOrder = 5;
5784
+ }
5785
+ get selectionOrder() {
5786
+ return this._selectionOrder;
5758
5787
  }
5759
5788
  init() {
5760
- console.log('Global.init()');
5789
+ console.log("Global.init()");
5761
5790
  }
5762
5791
  // --- getters/setters ---
5763
- get version() { return this._version; }
5764
- set corsProxyUrl(url) { this._corsProxyUrl = url; }
5765
- get corsProxyUrl() { return this._corsProxyUrl; }
5766
- get useCORSProxy() { return this._useCORSProxy; }
5767
- set useCORSProxy(enabled) { this._useCORSProxy = enabled; }
5768
- get debug() { return this._debug; }
5792
+ get version() {
5793
+ return this._version;
5794
+ }
5795
+ set corsProxyUrl(url) {
5796
+ this._corsProxyUrl = url;
5797
+ }
5798
+ get corsProxyUrl() {
5799
+ return this._corsProxyUrl;
5800
+ }
5801
+ get useCORSProxy() {
5802
+ return this._useCORSProxy;
5803
+ }
5804
+ set useCORSProxy(enabled) {
5805
+ this._useCORSProxy = enabled;
5806
+ }
5807
+ get debug() {
5808
+ return this._debug;
5809
+ }
5769
5810
  getHealpix(order) {
5770
5811
  if (this._healpix[order] === undefined) {
5771
5812
  // order is HEALPix "order" ⇒ nside = 2^order
@@ -5773,10 +5814,15 @@ class Global {
5773
5814
  }
5774
5815
  return this._healpix[order];
5775
5816
  }
5776
- get MAX_DECIMALS() { return this._maxDecimals; }
5777
- set insideSphere(v) { this._insideSphere = v; }
5778
- get insideSphere() { return this._insideSphere; }
5779
- get nsideForSelection() { return this._selectionnside; }
5817
+ get MAX_DECIMALS() {
5818
+ return this._maxDecimals;
5819
+ }
5820
+ set insideSphere(v) {
5821
+ this._insideSphere = v;
5822
+ }
5823
+ get insideSphere() {
5824
+ return this._insideSphere;
5825
+ }
5780
5826
  }
5781
5827
  const global = new Global();
5782
5828
  exports["default"] = global;
@@ -5867,7 +5913,6 @@ var Source_js_1 = __webpack_require__(146);
5867
5913
  Object.defineProperty(exports, "Source", ({ enumerable: true, get: function () { return Source_js_1.Source; } }));
5868
5914
  var Footprint_js_1 = __webpack_require__(2475);
5869
5915
  Object.defineProperty(exports, "Footprint", ({ enumerable: true, get: function () { return Footprint_js_1.Footprint; } }));
5870
- console.log('astroviewer UMD loaded');
5871
5916
 
5872
5917
 
5873
5918
  /***/ },
@@ -7857,7 +7902,8 @@ class Source {
7857
7902
  }
7858
7903
  computeHealpixPixel() {
7859
7904
  // Get Healpix instance from global
7860
- const healpix = Global_js_1.default.getHealpix(Global_js_1.default.nsideForSelection);
7905
+ // const healpix: Healpix = global.getHealpix(global.nsideForSelection);
7906
+ const healpix = Global_js_1.default.getHealpix(Global_js_1.default.selectionOrder);
7861
7907
  const vec3 = new healpix_1.Vec3(this._point.x, this._point.y, this._point.z);
7862
7908
  const ptg = new healpix_1.Pointing(vec3, false);
7863
7909
  this._h_pix = healpix.ang2pix(ptg, false);
@@ -8145,7 +8191,7 @@ class CatalogueGL {
8145
8191
  _oldMouseCoords;
8146
8192
  _metadataManager;
8147
8193
  _isVisible = true;
8148
- _shapeColor = '#8F00FF';
8194
+ _shapeColor = "#8F00FF";
8149
8195
  _healpixDensityMap;
8150
8196
  _providerUrl;
8151
8197
  _catalogueShaderProgram;
@@ -8154,7 +8200,7 @@ class CatalogueGL {
8154
8200
  this._webgl = webgl;
8155
8201
  this._ready = false;
8156
8202
  this._visibleTilesManager = visibleTilesManager;
8157
- this.TYPE = 'SOURCE_CATALOGUE';
8203
+ this.TYPE = "SOURCE_CATALOGUE";
8158
8204
  this._name = catalogueName;
8159
8205
  this._description = catalogueDescription;
8160
8206
  this._providerUrl = providerUrl;
@@ -8172,7 +8218,7 @@ class CatalogueGL {
8172
8218
  this._oldMouseCoords = null;
8173
8219
  this._healpixDensityMap = new Map();
8174
8220
  // this.catalogueProps = new CatalogueProps(metadataManager, defaultColor);
8175
- // call catalogueShaderProgram to init shaders if they are not yet initialised
8221
+ // call catalogueShaderProgram to init shaders if they are not yet initialised
8176
8222
  this._catalogueShaderProgram = new CatalogueShaderProgram_js_1.CatalogueShaderProgram(this._webgl);
8177
8223
  this._catalogueShaderProgram.shaderProgram;
8178
8224
  // catalogueShaderProgram.shaderProgram
@@ -8217,7 +8263,7 @@ class CatalogueGL {
8217
8263
  }
8218
8264
  return {
8219
8265
  min: Number(min),
8220
- max: Number(max)
8266
+ max: Number(max),
8221
8267
  };
8222
8268
  }
8223
8269
  get metadataManager() {
@@ -8266,7 +8312,7 @@ class CatalogueGL {
8266
8312
  const raw = Number(source.getDetailByindex(idx));
8267
8313
  const min = Number(minmax.min);
8268
8314
  const max = Number(minmax.max);
8269
- const norm = (raw - min) / Math.max(1e-12, (max - min));
8315
+ const norm = (raw - min) / Math.max(1e-12, max - min);
8270
8316
  const size = norm * (20 - 8) + 8;
8271
8317
  source.shapeSize = size;
8272
8318
  }
@@ -8303,7 +8349,7 @@ class CatalogueGL {
8303
8349
  const raw = Number(source.getDetailByindex(idx));
8304
8350
  const min = Number(minmax.min);
8305
8351
  const max = Number(minmax.max);
8306
- const norm = (raw - min) / Math.max(1e-12, (max - min));
8352
+ const norm = (raw - min) / Math.max(1e-12, max - min);
8307
8353
  // map [0,1] -> [1,-1]
8308
8354
  source.brightnessFactor = -(norm * 2 - 1);
8309
8355
  }
@@ -8333,7 +8379,7 @@ class CatalogueGL {
8333
8379
  for (let j = 0; j < in_data.length; j++) {
8334
8380
  const point = new Point_js_1.Point({
8335
8381
  raDeg: in_data[j][raDataIndex],
8336
- decDeg: in_data[j][decDataIndex]
8382
+ decDeg: in_data[j][decDataIndex],
8337
8383
  }, CoordsType_js_1.CoordsType.ASTRO);
8338
8384
  const source = new Source_js_1.Source(point, in_data[j]);
8339
8385
  // Ensure optional fields exist
@@ -8404,7 +8450,8 @@ class CatalogueGL {
8404
8450
  if (i >= 0) {
8405
8451
  this.hoveredIndexes.splice(i, 1);
8406
8452
  this.vertexCataloguePosition[base + 3] = 0.0; // not hovered
8407
- this.vertexCataloguePosition[base + 4] = this._sources[sIdx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8453
+ this.vertexCataloguePosition[base + 4] =
8454
+ this._sources[sIdx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8408
8455
  }
8409
8456
  }
8410
8457
  }
@@ -8428,7 +8475,8 @@ class CatalogueGL {
8428
8475
  if (i >= 0) {
8429
8476
  this.selectedIndexes.splice(i, 1);
8430
8477
  this.vertexCataloguePosition[base + 3] = 0.0; // not selected
8431
- this.vertexCataloguePosition[base + 4] = this._sources[sIdx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8478
+ this.vertexCataloguePosition[base + 4] =
8479
+ this._sources[sIdx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8432
8480
  }
8433
8481
  }
8434
8482
  }
@@ -8459,9 +8507,11 @@ class CatalogueGL {
8459
8507
  // hovered flag
8460
8508
  this.vertexCataloguePosition[positionIndex + 3] = 0.0;
8461
8509
  // size
8462
- this.vertexCataloguePosition[positionIndex + 4] = currSource.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8510
+ this.vertexCataloguePosition[positionIndex + 4] =
8511
+ currSource.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8463
8512
  // brightness
8464
- this.vertexCataloguePosition[positionIndex + 5] = currSource.brightnessFactor ?? 0.0;
8513
+ this.vertexCataloguePosition[positionIndex + 5] =
8514
+ currSource.brightnessFactor ?? 0.0;
8465
8515
  positionIndex += CatalogueGL.ELEM_SIZE;
8466
8516
  }
8467
8517
  this._webgl.bufferData(this._webgl.ARRAY_BUFFER, this.vertexCataloguePosition, this._webgl.STATIC_DRAW);
@@ -8495,50 +8545,8 @@ class CatalogueGL {
8495
8545
  return 0.0001;
8496
8546
  }
8497
8547
  }
8498
- checkClicking(in_mouseHelper) {
8499
- if (in_mouseHelper.x == null || in_mouseHelper.y == null || in_mouseHelper.z == null) {
8500
- console.log('CatalogueGL.checkClicking: missing mouse coords');
8501
- return [];
8502
- }
8503
- const clickedIndexes = [];
8504
- const mousePix = in_mouseHelper.computeNpix();
8505
- if (mousePix != null && this._healpixDensityMap.has(mousePix)) {
8506
- const candidates = this._healpixDensityMap.get(mousePix);
8507
- const selR = this.getSelectionRadius();
8508
- for (let i = 0; i < candidates.length; i++) {
8509
- const sourceIdx = candidates[i];
8510
- const source = this._sources[sourceIdx];
8511
- if (!source)
8512
- continue;
8513
- const dx = source.point.x - in_mouseHelper.x;
8514
- const dy = source.point.y - in_mouseHelper.y;
8515
- const dz = source.point.z - in_mouseHelper.z;
8516
- const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
8517
- if (dist <= selR) {
8518
- clickedIndexes.push(sourceIdx);
8519
- }
8520
- }
8521
- }
8522
- return clickedIndexes;
8523
- }
8524
- // private setSelectedIndexes(nextSelected: number[]) {
8525
- // const deduped = Array.from(new Set(nextSelected))
8526
- // .filter((idx) => idx >= 0 && idx < this._sources.length);
8527
- // if (this.vertexCataloguePosition.length) {
8528
- // for (const prevIdx of this.selectedIndexes) {
8529
- // if (deduped.includes(prevIdx)) continue;
8530
- // const base = prevIdx * CatalogueGL.ELEM_SIZE;
8531
- // if (base + 4 >= this.vertexCataloguePosition.length) continue;
8532
- // if (!this.hoveredIndexes.includes(prevIdx) && !this.extHoveredIndexes.includes(prevIdx)) {
8533
- // this.vertexCataloguePosition[base + 3] = 0.0;
8534
- // }
8535
- // this.vertexCataloguePosition[base + 4] = this._sources[prevIdx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8536
- // }
8537
- // }
8538
- // this.selectedIndexes = deduped;
8539
- // }
8540
8548
  setSelectedIndexes(selectedIndex) {
8541
- selectedIndex.forEach(idx => {
8549
+ selectedIndex.forEach((idx) => {
8542
8550
  if (idx < 0 || idx >= this._sources.length)
8543
8551
  return;
8544
8552
  const base = idx * CatalogueGL.ELEM_SIZE;
@@ -8547,12 +8555,14 @@ class CatalogueGL {
8547
8555
  if (this.selectedIndexes.includes(idx)) {
8548
8556
  this.selectedIndexes.splice(this.selectedIndexes.indexOf(idx), 1);
8549
8557
  this.vertexCataloguePosition[base + 3] = 0.0; // not selected
8550
- this.vertexCataloguePosition[base + 4] = this._sources[idx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8558
+ this.vertexCataloguePosition[base + 4] =
8559
+ this._sources[idx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8551
8560
  }
8552
8561
  else {
8553
8562
  this.selectedIndexes.push(idx);
8554
8563
  this.vertexCataloguePosition[base + 3] = 2.0; // selected
8555
- this.vertexCataloguePosition[base + 4] = this._sources[idx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8564
+ this.vertexCataloguePosition[base + 4] =
8565
+ this._sources[idx]?.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
8556
8566
  }
8557
8567
  });
8558
8568
  }
@@ -8569,7 +8579,7 @@ class CatalogueGL {
8569
8579
  };
8570
8580
  }
8571
8581
  const sources = [];
8572
- pickedIndexes.forEach(idx => {
8582
+ pickedIndexes.forEach((idx) => {
8573
8583
  const source = this._sources[idx];
8574
8584
  if (source)
8575
8585
  sources.push(source);
@@ -8599,7 +8609,7 @@ class CatalogueGL {
8599
8609
  }
8600
8610
  const selectionState = [];
8601
8611
  const selectedSources = [];
8602
- clickedIndexes.forEach(idx => {
8612
+ clickedIndexes.forEach((idx) => {
8603
8613
  const source = this._sources[idx];
8604
8614
  if (!source)
8605
8615
  return;
@@ -8617,31 +8627,43 @@ class CatalogueGL {
8617
8627
  const idx = this.hoveredIndexes[0];
8618
8628
  return this._sources[idx] ?? null;
8619
8629
  }
8620
- checkHovering(in_mouseHelper) {
8621
- if (in_mouseHelper.x == null || in_mouseHelper.y == null || in_mouseHelper.z == null) {
8622
- console.log('CatalogueGL.checkHovering: missing mouse coords');
8623
- return [];
8630
+ findNearestSourceIndex(in_mouseHelper) {
8631
+ if (in_mouseHelper.x == null ||
8632
+ in_mouseHelper.y == null ||
8633
+ in_mouseHelper.z == null) {
8634
+ return null;
8624
8635
  }
8625
- const hoveredIndexes = [];
8626
8636
  const mousePix = in_mouseHelper.computeNpix();
8627
- if (mousePix != null && this._healpixDensityMap.has(mousePix)) {
8628
- const candidates = this._healpixDensityMap.get(mousePix);
8629
- const selR = this.getSelectionRadius();
8630
- for (let i = 0; i < candidates.length; i++) {
8631
- const sourceIdx = candidates[i];
8632
- const source = this._sources[sourceIdx];
8633
- if (!source)
8634
- continue;
8635
- const dx = source.point.x - in_mouseHelper.x;
8636
- const dy = source.point.y - in_mouseHelper.y;
8637
- const dz = source.point.z - in_mouseHelper.z;
8638
- const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
8639
- if (dist <= selR) {
8640
- hoveredIndexes.push(sourceIdx);
8641
- }
8637
+ if (mousePix == null)
8638
+ return null;
8639
+ const candidates = this._healpixDensityMap.get(mousePix);
8640
+ if (!candidates?.length)
8641
+ return null;
8642
+ const selR = this.getSelectionRadius();
8643
+ let nearestIndex = null;
8644
+ let nearestDistance = Number.POSITIVE_INFINITY;
8645
+ for (const sourceIdx of candidates) {
8646
+ const source = this._sources[sourceIdx];
8647
+ if (!source)
8648
+ continue;
8649
+ const dx = source.point.x - in_mouseHelper.x;
8650
+ const dy = source.point.y - in_mouseHelper.y;
8651
+ const dz = source.point.z - in_mouseHelper.z;
8652
+ const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
8653
+ if (dist <= selR && dist < nearestDistance) {
8654
+ nearestDistance = dist;
8655
+ nearestIndex = sourceIdx;
8642
8656
  }
8643
8657
  }
8644
- return hoveredIndexes;
8658
+ return nearestIndex;
8659
+ }
8660
+ checkClicking(in_mouseHelper) {
8661
+ const nearestIndex = this.findNearestSourceIndex(in_mouseHelper);
8662
+ return nearestIndex == null ? [] : [nearestIndex];
8663
+ }
8664
+ checkHovering(in_mouseHelper) {
8665
+ const nearestIndex = this.findNearestSourceIndex(in_mouseHelper);
8666
+ return nearestIndex == null ? [] : [nearestIndex];
8645
8667
  }
8646
8668
  /**
8647
8669
  * @param in_mMatrix Model matrix the current catalogue is associated to (e.g. HiPS matrix)
@@ -8688,7 +8710,8 @@ class CatalogueGL {
8688
8710
  const base = this.hoveredIndexes[k] * CatalogueGL.ELEM_SIZE;
8689
8711
  // if (this.vertexCataloguePosition[base + 3] == 2.0) continue; // selected, skip hover
8690
8712
  this.vertexCataloguePosition[base + 3] = 0.0; // not hovered
8691
- this.vertexCataloguePosition[base + 4] = this._sources[this.hoveredIndexes[k]].shapeSize; // size
8713
+ this.vertexCataloguePosition[base + 4] =
8714
+ this._sources[this.hoveredIndexes[k]].shapeSize; // size
8692
8715
  }
8693
8716
  // Hover logic on mouse move
8694
8717
  if (in_mouseHelper != null && in_mouseHelper.xyz !== this._oldMouseCoords) {
@@ -10313,11 +10336,9 @@ class FootprintSetGL {
10313
10336
  _metadataManager;
10314
10337
  _providerUrl;
10315
10338
  _footprintShaderProgram;
10316
- _visibleTilesManager;
10317
- constructor(fsetName, fsetDescription, providerUrl, metadataManager, webgl, visibleTilesManager) {
10339
+ constructor(fsetName, fsetDescription, providerUrl, metadataManager, webgl) {
10318
10340
  this._webgl = webgl;
10319
10341
  this._ready = false;
10320
- this._visibleTilesManager = visibleTilesManager;
10321
10342
  this.TYPE = "FOOTPRINT_SET";
10322
10343
  this._name = fsetName;
10323
10344
  this._description = fsetDescription;
@@ -11633,8 +11654,14 @@ class HealpixGrid extends AbstractSkyEntity_js_1.AbstractSkyEntity {
11633
11654
  // FIX: pass model & pMatrix to match FoVUtils TS signature
11634
11655
  const center = FoVUtils_js_1.FoVUtils.getCenterJ2000(gl.canvas, this, this._webgl, camera, pMatrix);
11635
11656
  const fovMin = (this.getMinFoV() * Math.PI) / 180 / 2;
11657
+ const visibleHealpix = Global_js_1.default.getHealpix(this._visibleorder);
11658
+ const maxPixel = visibleHealpix.getNPix();
11636
11659
  for (let p = 0; p < pixels.length; p++) {
11637
- const pixCenter = Global_js_1.default.getHealpix(this._visibleorder).pix2vec(pixels[p]);
11660
+ const pixel = pixels[p];
11661
+ if (!Number.isInteger(pixel) || pixel < 0 || pixel >= maxPixel) {
11662
+ continue;
11663
+ }
11664
+ const pixCenter = visibleHealpix.pix2vec(pixel);
11638
11665
  // const pixCenter = (global.getHealpix(global.order).pix2vec(pixels[p]) as BoundVec);
11639
11666
  const point = new Point_js_1.Point({ x: pixCenter.x, y: pixCenter.y, z: pixCenter.z }, CoordsType_js_1.CoordsType.CARTESIAN);
11640
11667
  const distance = GeomUtils_js_1.default.orthodromicDistance(center, point);
@@ -12062,6 +12089,7 @@ class AllSky {
12062
12089
  async loadFits() {
12063
12090
  try {
12064
12091
  this._fitsTile = await (0, FitsTileLoader_js_1.loadFitsTile)(this._texurl);
12092
+ this._hips.observeFITSDataRange(this._fitsTile);
12065
12093
  this.textureLoaded();
12066
12094
  this.initModelBuffer();
12067
12095
  this._textureLoaded = true;
@@ -12106,30 +12134,7 @@ class AllSky {
12106
12134
  }
12107
12135
  }
12108
12136
  getFitsDataRange() {
12109
- const hipsRange = this._hips.dataRange;
12110
- if (hipsRange.min !== undefined &&
12111
- hipsRange.max !== undefined &&
12112
- Number.isFinite(hipsRange.min) &&
12113
- Number.isFinite(hipsRange.max) &&
12114
- hipsRange.max > hipsRange.min) {
12115
- return {
12116
- min: hipsRange.min,
12117
- max: hipsRange.max,
12118
- };
12119
- }
12120
- const fits = this._fitsTile;
12121
- if (fits &&
12122
- fits.dataMin !== null &&
12123
- fits.dataMax !== null &&
12124
- Number.isFinite(fits.dataMin) &&
12125
- Number.isFinite(fits.dataMax) &&
12126
- fits.dataMax > fits.dataMin) {
12127
- return {
12128
- min: fits.dataMin,
12129
- max: fits.dataMax,
12130
- };
12131
- }
12132
- return null;
12137
+ return this._hips.getFITSDisplayRange(this._fitsTile);
12133
12138
  }
12134
12139
  initModelBuffer() {
12135
12140
  const gl = this._webgl;
@@ -12243,7 +12248,7 @@ class AllSky {
12243
12248
  console.error(`[AllSky] No display range available for FITS atlas ${this._texurl}`);
12244
12249
  return false;
12245
12250
  }
12246
- this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max);
12251
+ this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max, this._hips.fitsStretch.scaleFunctionIndex, this._hips.fitsStretch.scaleParam);
12247
12252
  }
12248
12253
  else {
12249
12254
  this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, false);
@@ -12380,6 +12385,7 @@ class AncestorTile {
12380
12385
  async loadFits() {
12381
12386
  try {
12382
12387
  this._fitsTile = await (0, FitsTileLoader_js_1.loadFitsTile)(this._texurl);
12388
+ this._hips.observeFITSDataRange(this._fitsTile);
12383
12389
  this.textureLoaded();
12384
12390
  const fits = this._fitsTile;
12385
12391
  if (!fits) {
@@ -12437,30 +12443,7 @@ class AncestorTile {
12437
12443
  }
12438
12444
  }
12439
12445
  getFitsDataRange() {
12440
- const hipsRange = this._hips.dataRange;
12441
- if (hipsRange.min !== undefined &&
12442
- hipsRange.max !== undefined &&
12443
- Number.isFinite(hipsRange.min) &&
12444
- Number.isFinite(hipsRange.max) &&
12445
- hipsRange.max > hipsRange.min) {
12446
- return {
12447
- min: hipsRange.min,
12448
- max: hipsRange.max,
12449
- };
12450
- }
12451
- const fits = this._fitsTile;
12452
- if (fits &&
12453
- fits.dataMin !== null &&
12454
- fits.dataMax !== null &&
12455
- Number.isFinite(fits.dataMin) &&
12456
- Number.isFinite(fits.dataMax) &&
12457
- fits.dataMax > fits.dataMin) {
12458
- return {
12459
- min: fits.dataMin,
12460
- max: fits.dataMax,
12461
- };
12462
- }
12463
- return null;
12446
+ return this._hips.getFITSDisplayRange(this._fitsTile);
12464
12447
  }
12465
12448
  initModelBuffer() {
12466
12449
  const gl = this._webgl;
@@ -12560,7 +12543,7 @@ class AncestorTile {
12560
12543
  console.error(`[AncestorTile] No display range available for FITS tile ${this._texurl}`);
12561
12544
  return false;
12562
12545
  }
12563
- this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max);
12546
+ this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max, this._hips.fitsStretch.scaleFunctionIndex, this._hips.fitsStretch.scaleParam);
12564
12547
  }
12565
12548
  else {
12566
12549
  this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, false);
@@ -12637,6 +12620,9 @@ var __webpack_unused_export__;
12637
12620
  __webpack_unused_export__ = ({ value: true });
12638
12621
  exports.loadFitsTile = loadFitsTile;
12639
12622
  const jsfitsio_1 = __webpack_require__(4971);
12623
+ const ROBUST_SAMPLE_COUNT = 8192;
12624
+ const ROBUST_LOW_PERCENTILE = 0.005;
12625
+ const ROBUST_HIGH_PERCENTILE = 0.995;
12640
12626
  async function loadFitsTile(url) {
12641
12627
  const fitsFile = await jsfitsio_1.FITSParser.loadFITSFile(url);
12642
12628
  if (!fitsFile?.primaryHDU) {
@@ -12666,22 +12652,57 @@ async function loadFitsTile(url) {
12666
12652
  const dataMin = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.DATAMIN);
12667
12653
  const dataMax = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.DATAMAX);
12668
12654
  const pixels = new Float32Array(data.length);
12655
+ let physicalMin = null;
12656
+ let physicalMax = null;
12657
+ const robustSamples = [];
12658
+ const sampleStep = Math.max(1, Math.floor(data.length / ROBUST_SAMPLE_COUNT));
12669
12659
  for (let i = 0; i < data.length; i++) {
12670
12660
  const rawValue = data[i];
12671
12661
  if (!Number.isFinite(rawValue) || (blank !== null && rawValue === blank)) {
12672
12662
  pixels[i] = Number.NaN;
12673
12663
  continue;
12674
12664
  }
12675
- pixels[i] = rawValue * bscale + bzero;
12665
+ const physicalValue = rawValue * bscale + bzero;
12666
+ pixels[i] = physicalValue;
12667
+ if (Number.isFinite(physicalValue)) {
12668
+ physicalMin =
12669
+ physicalMin === null ? physicalValue : Math.min(physicalMin, physicalValue);
12670
+ physicalMax =
12671
+ physicalMax === null ? physicalValue : Math.max(physicalMax, physicalValue);
12672
+ if (i % sampleStep === 0) {
12673
+ robustSamples.push(physicalValue);
12674
+ }
12675
+ }
12676
12676
  }
12677
+ const robustRange = computeRobustRange(robustSamples);
12677
12678
  return {
12678
12679
  width,
12679
12680
  height,
12680
12681
  pixels,
12681
12682
  dataMin,
12682
12683
  dataMax,
12684
+ physicalMin,
12685
+ physicalMax,
12686
+ robustMin: robustRange?.min ?? null,
12687
+ robustMax: robustRange?.max ?? null,
12683
12688
  };
12684
12689
  }
12690
+ function computeRobustRange(samples) {
12691
+ if (samples.length === 0) {
12692
+ return null;
12693
+ }
12694
+ samples.sort((a, b) => a - b);
12695
+ const min = percentile(samples, ROBUST_LOW_PERCENTILE);
12696
+ const max = percentile(samples, ROBUST_HIGH_PERCENTILE);
12697
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
12698
+ return null;
12699
+ }
12700
+ return { min, max };
12701
+ }
12702
+ function percentile(sortedValues, p) {
12703
+ const index = Math.min(sortedValues.length - 1, Math.max(0, Math.round((sortedValues.length - 1) * p)));
12704
+ return sortedValues[index];
12705
+ }
12685
12706
  function getNumericHeaderValue(header, key) {
12686
12707
  const item = header.findById(key);
12687
12708
  if (!item) {
@@ -12885,6 +12906,21 @@ const ColorMaps_js_1 = __importDefault(__webpack_require__(619));
12885
12906
  const AncestorTile_js_1 = __importDefault(__webpack_require__(2885));
12886
12907
  const AllSky_js_1 = __importDefault(__webpack_require__(2368));
12887
12908
  const HiPSCoverage_js_1 = __webpack_require__(9912);
12909
+ const FITS_SCALE_FUNCTION_INDEX = {
12910
+ linear: 0,
12911
+ sqrt: 1,
12912
+ log: 2,
12913
+ asinh: 3,
12914
+ gamma: 4,
12915
+ };
12916
+ const DEFAULT_FITS_SCALE_PARAM = {
12917
+ linear: 1,
12918
+ sqrt: 1,
12919
+ log: 100,
12920
+ asinh: 10,
12921
+ gamma: 0.5,
12922
+ };
12923
+ const MAX_ROBUST_TILE_RANGES = 512;
12888
12924
  class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12889
12925
  _ancestorTiles;
12890
12926
  _allSkyTile;
@@ -12901,6 +12937,13 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12901
12937
  samplerIdx = 0;
12902
12938
  colorMapIdx = 0;
12903
12939
  colorMap = ColorMaps_js_1.default["native"];
12940
+ _fitsStretch = {
12941
+ scaleFunction: "linear",
12942
+ scaleFunctionIndex: FITS_SCALE_FUNCTION_INDEX.linear,
12943
+ scaleParam: DEFAULT_FITS_SCALE_PARAM.linear,
12944
+ rangeMode: "robust",
12945
+ };
12946
+ _robustFITSRanges = [];
12904
12947
  _healpixGrid;
12905
12948
  // exposed read-only helpers
12906
12949
  get maxOrder() {
@@ -13136,6 +13179,137 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
13136
13179
  get dataRange() {
13137
13180
  return this._descriptor.dataRange;
13138
13181
  }
13182
+ get fitsStretch() {
13183
+ return this._fitsStretch;
13184
+ }
13185
+ setFITSScaleFunction(scaleFunction, scaleParam) {
13186
+ const scaleFunctionIndex = FITS_SCALE_FUNCTION_INDEX[scaleFunction];
13187
+ if (scaleFunctionIndex === undefined) {
13188
+ throw new Error(`Unsupported FITS scale function: ${scaleFunction}`);
13189
+ }
13190
+ const defaultParam = DEFAULT_FITS_SCALE_PARAM[scaleFunction];
13191
+ const param = scaleParam ?? defaultParam;
13192
+ if (!Number.isFinite(param) || param <= 0) {
13193
+ throw new Error(`Invalid FITS scale parameter: ${param}`);
13194
+ }
13195
+ this._fitsStretch = {
13196
+ ...this._fitsStretch,
13197
+ scaleFunction,
13198
+ scaleFunctionIndex,
13199
+ scaleParam: param,
13200
+ };
13201
+ }
13202
+ setFITSRangeMode(rangeMode) {
13203
+ if (rangeMode !== "robust" && rangeMode !== "hips" && rangeMode !== "tile") {
13204
+ throw new Error(`Unsupported FITS range mode: ${rangeMode}`);
13205
+ }
13206
+ this._fitsStretch = {
13207
+ ...this._fitsStretch,
13208
+ rangeMode,
13209
+ };
13210
+ }
13211
+ observeFITSDataRange(fits) {
13212
+ if (fits.robustMin === null ||
13213
+ fits.robustMax === null ||
13214
+ !Number.isFinite(fits.robustMin) ||
13215
+ !Number.isFinite(fits.robustMax) ||
13216
+ fits.robustMax <= fits.robustMin) {
13217
+ return;
13218
+ }
13219
+ this._robustFITSRanges.push({
13220
+ min: fits.robustMin,
13221
+ max: fits.robustMax,
13222
+ });
13223
+ if (this._robustFITSRanges.length > MAX_ROBUST_TILE_RANGES) {
13224
+ this._robustFITSRanges.shift();
13225
+ }
13226
+ }
13227
+ getFITSDisplayRange(fits) {
13228
+ const hipsRange = this.getHiPSDataRange();
13229
+ if (this._fitsStretch.rangeMode === "hips" && hipsRange) {
13230
+ return hipsRange;
13231
+ }
13232
+ if (this._fitsStretch.rangeMode === "robust") {
13233
+ const robustRange = this.getRobustFITSRange() ?? this.getTileRobustRange(fits);
13234
+ if (robustRange) {
13235
+ return robustRange;
13236
+ }
13237
+ }
13238
+ const tileRange = this.getTilePhysicalRange(fits) ?? this.getTileHeaderRange(fits);
13239
+ if (tileRange) {
13240
+ return tileRange;
13241
+ }
13242
+ return hipsRange;
13243
+ }
13244
+ getHiPSDataRange() {
13245
+ const hipsRange = this.dataRange;
13246
+ if (hipsRange.min !== undefined &&
13247
+ hipsRange.max !== undefined &&
13248
+ Number.isFinite(hipsRange.min) &&
13249
+ Number.isFinite(hipsRange.max) &&
13250
+ hipsRange.max > hipsRange.min) {
13251
+ return {
13252
+ min: hipsRange.min,
13253
+ max: hipsRange.max,
13254
+ };
13255
+ }
13256
+ return null;
13257
+ }
13258
+ getRobustFITSRange() {
13259
+ if (this._robustFITSRanges.length === 0) {
13260
+ return null;
13261
+ }
13262
+ const lows = this._robustFITSRanges.map((range) => range.min).sort((a, b) => a - b);
13263
+ const highs = this._robustFITSRanges.map((range) => range.max).sort((a, b) => a - b);
13264
+ const min = lows[Math.floor((lows.length - 1) * 0.1)];
13265
+ const max = highs[Math.ceil((highs.length - 1) * 0.9)];
13266
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
13267
+ return null;
13268
+ }
13269
+ return { min, max };
13270
+ }
13271
+ getTileRobustRange(fits) {
13272
+ if (fits &&
13273
+ fits.robustMin !== null &&
13274
+ fits.robustMax !== null &&
13275
+ Number.isFinite(fits.robustMin) &&
13276
+ Number.isFinite(fits.robustMax) &&
13277
+ fits.robustMax > fits.robustMin) {
13278
+ return {
13279
+ min: fits.robustMin,
13280
+ max: fits.robustMax,
13281
+ };
13282
+ }
13283
+ return null;
13284
+ }
13285
+ getTilePhysicalRange(fits) {
13286
+ if (fits &&
13287
+ fits.physicalMin !== null &&
13288
+ fits.physicalMax !== null &&
13289
+ Number.isFinite(fits.physicalMin) &&
13290
+ Number.isFinite(fits.physicalMax) &&
13291
+ fits.physicalMax > fits.physicalMin) {
13292
+ return {
13293
+ min: fits.physicalMin,
13294
+ max: fits.physicalMax,
13295
+ };
13296
+ }
13297
+ return null;
13298
+ }
13299
+ getTileHeaderRange(fits) {
13300
+ if (fits &&
13301
+ fits.dataMin !== null &&
13302
+ fits.dataMax !== null &&
13303
+ Number.isFinite(fits.dataMin) &&
13304
+ Number.isFinite(fits.dataMax) &&
13305
+ fits.dataMax > fits.dataMin) {
13306
+ return {
13307
+ min: fits.dataMin,
13308
+ max: fits.dataMax,
13309
+ };
13310
+ }
13311
+ return null;
13312
+ }
13139
13313
  getCurrentHealpixOrder() {
13140
13314
  return this._visibleorder;
13141
13315
  }
@@ -13646,6 +13820,7 @@ class Tile {
13646
13820
  async loadFits() {
13647
13821
  try {
13648
13822
  this._fitsTile = await (0, FitsTileLoader_js_1.loadFitsTile)(this._texurl);
13823
+ this._hips.observeFITSDataRange(this._fitsTile);
13649
13824
  this._ready = true;
13650
13825
  }
13651
13826
  catch (error) {
@@ -13784,30 +13959,7 @@ class Tile {
13784
13959
  gl.bufferData(gl.ARRAY_BUFFER, this.vertexPosition[qidx], gl.STATIC_DRAW);
13785
13960
  }
13786
13961
  getFitsDataRange() {
13787
- const hipsRange = this._hips.dataRange;
13788
- if (hipsRange.min !== undefined &&
13789
- hipsRange.max !== undefined &&
13790
- Number.isFinite(hipsRange.min) &&
13791
- Number.isFinite(hipsRange.max) &&
13792
- hipsRange.max > hipsRange.min) {
13793
- return {
13794
- min: hipsRange.min,
13795
- max: hipsRange.max,
13796
- };
13797
- }
13798
- const fits = this._fitsTile;
13799
- if (fits &&
13800
- fits.dataMin !== null &&
13801
- fits.dataMax !== null &&
13802
- Number.isFinite(fits.dataMin) &&
13803
- Number.isFinite(fits.dataMax) &&
13804
- fits.dataMax > fits.dataMin) {
13805
- return {
13806
- min: fits.dataMin,
13807
- max: fits.dataMax,
13808
- };
13809
- }
13810
- return null;
13962
+ return this._hips.getFITSDisplayRange(this._fitsTile);
13811
13963
  }
13812
13964
  get inView() {
13813
13965
  return this._inView;
@@ -13911,7 +14063,7 @@ class Tile {
13911
14063
  console.error(`[Tile] No display range available for FITS tile ${this._texurl}`);
13912
14064
  return;
13913
14065
  }
13914
- hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max);
14066
+ hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max, this._hips.fitsStretch.scaleFunctionIndex, this._hips.fitsStretch.scaleParam);
13915
14067
  }
13916
14068
  else {
13917
14069
  hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, false);
@@ -14489,7 +14641,9 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14489
14641
  const orders = Array.from(byOrder.keys()).sort((a, b) => a - b);
14490
14642
  for (const order of orders) {
14491
14643
  for (const coord of byOrder.get(order) ?? []) {
14492
- this._tiles.get(this.tileKey(coord))?.draw(pMatrix, vMatrix, mMatrix, this._descriptor.color, this._descriptor.wireframe);
14644
+ this._tiles
14645
+ .get(this.tileKey(coord))
14646
+ ?.draw(pMatrix, vMatrix, mMatrix, this._descriptor.color, this._descriptor.wireframe);
14493
14647
  }
14494
14648
  }
14495
14649
  if (wasCullFace)
@@ -14502,7 +14656,7 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14502
14656
  getDebugStats() {
14503
14657
  const tiles = Array.from(this._tiles.values());
14504
14658
  return {
14505
- activeBaseLayer: 'meships',
14659
+ activeBaseLayer: "meships",
14506
14660
  meshHiPSName: this._descriptor.name,
14507
14661
  meshHiPSUrl: this._descriptor.baseUrl,
14508
14662
  currentOrder: this._currentOrder,
@@ -14521,33 +14675,47 @@ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
14521
14675
  ? byOrder.pixels
14522
14676
  : [];
14523
14677
  if (pixels.length > 0) {
14524
- return pixels.map((ipix) => ({ order: this._currentOrder, ipix }));
14678
+ return pixels.map((ipix) => ({
14679
+ order: this._currentOrder,
14680
+ ipix,
14681
+ }));
14525
14682
  }
14526
14683
  const tileCount = 12 * 4 ** this._currentOrder;
14527
- return Array.from({ length: tileCount }, (_, ipix) => ({ order: this._currentOrder, ipix }));
14684
+ return Array.from({ length: tileCount }, (_, ipix) => ({
14685
+ order: this._currentOrder,
14686
+ ipix,
14687
+ }));
14528
14688
  }
14529
14689
  resolveCoverageTiles(visibleTiles) {
14530
14690
  const tiles = new Map();
14531
14691
  const add = (coord) => {
14532
- if (coord.order < this._descriptor.minOrder || coord.order > this._descriptor.maxOrder)
14692
+ if (coord.order < this._descriptor.minOrder ||
14693
+ coord.order > this._descriptor.maxOrder) {
14533
14694
  return;
14695
+ }
14534
14696
  tiles.set(this.tileKey(coord), coord);
14535
14697
  };
14536
14698
  for (const coord of visibleTiles) {
14537
14699
  add(coord);
14538
14700
  for (let order = coord.order - 1; order >= this._descriptor.minOrder; order--) {
14539
14701
  const shift = 2 * (coord.order - order);
14540
- add({ order, ipix: coord.ipix >> shift });
14702
+ add({
14703
+ order,
14704
+ ipix: coord.ipix >> shift,
14705
+ });
14541
14706
  }
14542
14707
  }
14543
14708
  const manager = this._healpixGrid.visibleTilesManager;
14544
14709
  const ancestorsMap = manager?.ancestorsMap;
14545
14710
  if (ancestorsMap) {
14546
14711
  for (const [order, ipixes] of ancestorsMap) {
14547
- if (order < this._descriptor.minOrder || order > this._descriptor.maxOrder)
14712
+ if (order < this._descriptor.minOrder ||
14713
+ order > this._descriptor.maxOrder) {
14548
14714
  continue;
14549
- for (const ipix of ipixes)
14715
+ }
14716
+ for (const ipix of ipixes) {
14550
14717
  add({ order, ipix });
14718
+ }
14551
14719
  }
14552
14720
  }
14553
14721
  return Array.from(tiles.values());
@@ -16164,6 +16332,9 @@ function normalizeLongitudeDeg(longitudeDeg) {
16164
16332
  *
16165
16333
  * See LICENSE.md, LICENSE-AGPL.md, and LICENSE-COMMERCIAL.md for details.
16166
16334
  */
16335
+ var __importDefault = (this && this.__importDefault) || function (mod) {
16336
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16337
+ };
16167
16338
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16168
16339
  exports.TerraFootprintSetGL = void 0;
16169
16340
  const FootprintSetGL_js_1 = __webpack_require__(592);
@@ -16172,6 +16343,8 @@ const Footprint_js_1 = __webpack_require__(2475);
16172
16343
  const MetadataColumn_js_1 = __webpack_require__(1072);
16173
16344
  const MetadataManager_js_1 = __webpack_require__(5403);
16174
16345
  const MetadataColumn_js_2 = __webpack_require__(1072);
16346
+ const Point_js_1 = __webpack_require__(6553);
16347
+ const GeomUtils_js_1 = __importDefault(__webpack_require__(2930));
16175
16348
  class TerraFootprintSetGL extends FootprintSetGL_js_1.FootprintSetGL {
16176
16349
  _kind = 'TerraFootprintSetGL';
16177
16350
  _coordsType = CoordsType_js_1.CoordsType.GEOGRAPHIC;
@@ -16190,6 +16363,23 @@ class TerraFootprintSetGL extends FootprintSetGL_js_1.FootprintSetGL {
16190
16363
  this._ready = true;
16191
16364
  this._bufferInitialised = false;
16192
16365
  }
16366
+ checkSelection(mouseHelper) {
16367
+ if (mouseHelper.x == null || mouseHelper.y == null || mouseHelper.z == null)
16368
+ return;
16369
+ const hoverState = this;
16370
+ hoverState._hoveredFootprints = [];
16371
+ this.totHoveredPoints = 0;
16372
+ const mousePoint = new Point_js_1.Point({ x: mouseHelper.x, y: mouseHelper.y, z: mouseHelper.z }, CoordsType_js_1.CoordsType.CARTESIAN);
16373
+ for (const footprint of this.footprintPolygons) {
16374
+ if (!footprint.selectionObj)
16375
+ continue;
16376
+ if (GeomUtils_js_1.default.checkPointInsidePolygon5(footprint.selectionObj, mousePoint)) {
16377
+ hoverState._hoveredFootprints.push(footprint);
16378
+ this.totHoveredPoints += footprint.totPoints;
16379
+ }
16380
+ }
16381
+ this.initHoveringBuffer();
16382
+ }
16193
16383
  createGeoJSONMetadataColumns(features) {
16194
16384
  const names = new Set();
16195
16385
  features.forEach(feature => Object.keys(feature.properties).forEach(name => names.add(name)));
@@ -16234,8 +16424,44 @@ exports.TerraFootprintSetGL = TerraFootprintSetGL;
16234
16424
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16235
16425
  exports.TerraPointSetGL = void 0;
16236
16426
  const CatalogueGL_js_1 = __webpack_require__(1232);
16427
+ const MetadataManager_js_1 = __webpack_require__(5403);
16428
+ const Point_js_1 = __webpack_require__(6553);
16429
+ const CoordsType_js_1 = __webpack_require__(8145);
16237
16430
  class TerraPointSetGL extends CatalogueGL_js_1.CatalogueGL {
16238
16431
  _kind = 'TerraPointSetGL';
16432
+ addSources(inData, columnsMeta) {
16433
+ this._ready = false;
16434
+ this._sources = [];
16435
+ const metadataManager = new MetadataManager_js_1.MetadataManager(columnsMeta);
16436
+ this._metadataManager = metadataManager;
16437
+ const lonDataIndex = metadataManager.selectedRaColumn?.index ?? -1;
16438
+ const latDataIndex = metadataManager.selectedDecColumn?.index ?? -1;
16439
+ if (lonDataIndex < 0 || latDataIndex < 0) {
16440
+ throw new Error(`(lon, lat) idx not defined (${lonDataIndex}, ${latDataIndex}) `);
16441
+ }
16442
+ for (const row of inData) {
16443
+ const point = new Point_js_1.Point({
16444
+ lonDeg: Number(row[lonDataIndex]),
16445
+ latDeg: Number(row[latDataIndex]),
16446
+ }, CoordsType_js_1.CoordsType.GEOGRAPHIC);
16447
+ this.addSource({
16448
+ point,
16449
+ details: row,
16450
+ healpixPixel: 0,
16451
+ shapeSize: CatalogueGL_js_1.CatalogueGL.STANDARD_SHAPE_SIZE,
16452
+ brightnessFactor: 3,
16453
+ getDetailByindex(index) {
16454
+ return index < 0 || index >= row.length ? undefined : row[index];
16455
+ },
16456
+ });
16457
+ }
16458
+ this._ready = true;
16459
+ this._bufferInitialised = false;
16460
+ }
16461
+ draw(inMatrix, inMouseHelper, viewMatrix, projectionMatrix) {
16462
+ this._oldMouseCoords = inMouseHelper?.xyz ?? null;
16463
+ super.draw(inMatrix, inMouseHelper, viewMatrix, projectionMatrix);
16464
+ }
16239
16465
  }
16240
16466
  exports.TerraPointSetGL = TerraPointSetGL;
16241
16467
 
@@ -16268,7 +16494,6 @@ class TerraPolylineSetGL {
16268
16494
  _providerUrl;
16269
16495
  _metadataManager;
16270
16496
  _webgl;
16271
- _visibleTilesManager;
16272
16497
  static ELEM_SIZE = 3;
16273
16498
  static BYTES_X_ELEM = new Float32Array().BYTES_PER_ELEMENT;
16274
16499
  _kind = 'TerraPolylineSetGL';
@@ -16279,13 +16504,12 @@ class TerraPolylineSetGL {
16279
16504
  paths = [];
16280
16505
  renderSegments = [];
16281
16506
  _polylineShaderProgram;
16282
- constructor(_name, _description, _providerUrl, _metadataManager, _webgl, _visibleTilesManager) {
16507
+ constructor(_name, _description, _providerUrl, _metadataManager, _webgl) {
16283
16508
  this._name = _name;
16284
16509
  this._description = _description;
16285
16510
  this._providerUrl = _providerUrl;
16286
16511
  this._metadataManager = _metadataManager;
16287
16512
  this._webgl = _webgl;
16288
- this._visibleTilesManager = _visibleTilesManager;
16289
16513
  this._polylineShaderProgram = new FootprintShaderProgram_js_1.FootprintShaderProgram(this._webgl);
16290
16514
  }
16291
16515
  addPath(points, metadata) {
@@ -16756,6 +16980,8 @@ class HiPSShaderProgram {
16756
16980
  textureMode: "uTextureMode",
16757
16981
  dataMin: "uDataMin",
16758
16982
  dataMax: "uDataMax",
16983
+ scaleFunction: "uScaleFunction",
16984
+ scaleParam: "uScaleParam",
16759
16985
  };
16760
16986
  this.gl_attributes = {
16761
16987
  vertex_pos: "aVertexPosition",
@@ -16770,6 +16996,8 @@ class HiPSShaderProgram {
16770
16996
  textureMode: new Array(8).fill(null),
16771
16997
  dataMin: new Array(8).fill(null),
16772
16998
  dataMax: new Array(8).fill(null),
16999
+ scaleFunction: new Array(8).fill(null),
17000
+ scaleParam: new Array(8).fill(null),
16773
17001
  layerOpacity: null,
16774
17002
  clorMapIdx: null,
16775
17003
  vertexPositionAttribute: -1,
@@ -16903,7 +17131,7 @@ class HiPSShaderProgram {
16903
17131
  }
16904
17132
  gl.useProgram(this.shaderProgram);
16905
17133
  }
16906
- setTextureDataMode(samplerIndex, fits, min, max) {
17134
+ setTextureDataMode(samplerIndex, fits, min, max, scaleFunction = 0, scaleParam = 1) {
16907
17135
  if (samplerIndex < 0 || samplerIndex >= 8) {
16908
17136
  throw new Error(`Invalid HiPS sampler index: ${samplerIndex}`);
16909
17137
  }
@@ -16924,12 +17152,20 @@ class HiPSShaderProgram {
16924
17152
  }
16925
17153
  const minLocation = this.locations.dataMin[samplerIndex];
16926
17154
  const maxLocation = this.locations.dataMax[samplerIndex];
17155
+ const scaleFunctionLocation = this.locations.scaleFunction[samplerIndex];
17156
+ const scaleParamLocation = this.locations.scaleParam[samplerIndex];
16927
17157
  if (minLocation) {
16928
17158
  gl.uniform1f(minLocation, min);
16929
17159
  }
16930
17160
  if (maxLocation) {
16931
17161
  gl.uniform1f(maxLocation, max);
16932
17162
  }
17163
+ if (scaleFunctionLocation) {
17164
+ gl.uniform1i(scaleFunctionLocation, scaleFunction);
17165
+ }
17166
+ if (scaleParamLocation) {
17167
+ gl.uniform1f(scaleParamLocation, scaleParam);
17168
+ }
16933
17169
  }
16934
17170
  enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx) {
16935
17171
  // const gl = global.gl
@@ -16945,6 +17181,8 @@ class HiPSShaderProgram {
16945
17181
  this.locations.textureMode[i] = gl.getUniformLocation(this.shaderProgram, `uTextureMode${i}`);
16946
17182
  this.locations.dataMin[i] = gl.getUniformLocation(this.shaderProgram, `uDataMin${i}`);
16947
17183
  this.locations.dataMax[i] = gl.getUniformLocation(this.shaderProgram, `uDataMax${i}`);
17184
+ this.locations.scaleFunction[i] = gl.getUniformLocation(this.shaderProgram, `uScaleFunction${i}`);
17185
+ this.locations.scaleParam[i] = gl.getUniformLocation(this.shaderProgram, `uScaleParam${i}`);
16948
17186
  if (this.locations.samplers[i]) {
16949
17187
  gl.uniform1i(this.locations.samplers[i], i);
16950
17188
  }
@@ -17281,7 +17519,7 @@ class ShaderManager {
17281
17519
  }
17282
17520
  static footprintVS() {
17283
17521
  return `#version 300 es
17284
- precision highp float;
17522
+ precision mediump float;
17285
17523
 
17286
17524
  layout(location = 0) in vec4 aCatPosition;
17287
17525
 
@@ -17323,7 +17561,7 @@ class ShaderManager {
17323
17561
  }
17324
17562
  static hipsNativeFS() {
17325
17563
  return `#version 300 es
17326
- precision mediump float;
17564
+ precision highp float;
17327
17565
 
17328
17566
  in vec2 vTextureCoord;
17329
17567
 
@@ -17389,7 +17627,7 @@ class ShaderManager {
17389
17627
  }
17390
17628
  static hipsGrayscaleFS() {
17391
17629
  return `#version 300 es
17392
- precision mediump float;
17630
+ precision highp float;
17393
17631
 
17394
17632
  in vec2 vTextureCoord;
17395
17633
 
@@ -17463,7 +17701,7 @@ class ShaderManager {
17463
17701
  }
17464
17702
  static hipsColorMapFS() {
17465
17703
  return `#version 300 es
17466
- precision mediump float;
17704
+ precision highp float;
17467
17705
 
17468
17706
  uniform float uLayerOpacity;
17469
17707
 
@@ -17568,6 +17806,36 @@ class ShaderManager {
17568
17806
  uniform int uTextureMode${index};
17569
17807
  uniform float uDataMin${index};
17570
17808
  uniform float uDataMax${index};
17809
+ uniform int uScaleFunction${index};
17810
+ uniform float uScaleParam${index};
17811
+
17812
+ float asinhCompat${index}(float value) {
17813
+ return log(value + sqrt(value * value + 1.0));
17814
+ }
17815
+
17816
+ float applyFitsScale${index}(float normalized) {
17817
+ float x = clamp(normalized, 0.0, 1.0);
17818
+
17819
+ if (uScaleFunction${index} == 1) {
17820
+ return sqrt(x);
17821
+ }
17822
+
17823
+ if (uScaleFunction${index} == 2) {
17824
+ float strength = max(uScaleParam${index}, 1.0);
17825
+ return log(1.0 + strength * x) / log(1.0 + strength);
17826
+ }
17827
+
17828
+ if (uScaleFunction${index} == 3) {
17829
+ float strength = max(uScaleParam${index}, 1.0);
17830
+ return asinhCompat${index}(strength * x) / asinhCompat${index}(strength);
17831
+ }
17832
+
17833
+ if (uScaleFunction${index} == 4) {
17834
+ return pow(x, max(uScaleParam${index}, 0.0001));
17835
+ }
17836
+
17837
+ return x;
17838
+ }
17571
17839
 
17572
17840
  vec4 sampleHiPSTexture${index}(vec2 uv) {
17573
17841
  vec4 color = texture(uSampler${index}, uv);
@@ -17591,10 +17859,12 @@ class ShaderManager {
17591
17859
  1.0
17592
17860
  );
17593
17861
 
17862
+ float scaled = applyFitsScale${index}(normalized);
17863
+
17594
17864
  return vec4(
17595
- normalized,
17596
- normalized,
17597
- normalized,
17865
+ scaled,
17866
+ scaled,
17867
+ scaled,
17598
17868
  1.0
17599
17869
  );
17600
17870
  }
@@ -18565,7 +18835,8 @@ class MouseHelper {
18565
18835
  computeNpix() {
18566
18836
  if (!this._xyz)
18567
18837
  return null;
18568
- const hp = Global_js_1.default.getHealpix(Global_js_1.default.nsideForSelection);
18838
+ // const hp: Healpix = global.getHealpix(global.nsideForSelection);
18839
+ const hp = Global_js_1.default.getHealpix(Global_js_1.default.selectionOrder);
18569
18840
  const v = new healpix_1.Vec3(this._xyz[0], this._xyz[1], this._xyz[2]);
18570
18841
  const ptg = new healpix_1.Pointing(v, false);
18571
18842
  return hp.ang2pix(ptg, false);