astro-viewer 3.6.0 → 3.7.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 (67) hide show
  1. package/dist/64.astroviewer.cjs +37 -0
  2. package/dist/64.astroviewer.cjs.map +1 -0
  3. package/dist/64.astroviewer.js +41 -0
  4. package/dist/64.astroviewer.js.map +1 -0
  5. package/dist/64.astroviewer.min.js +2 -0
  6. package/dist/64.astroviewer.min.js.map +1 -0
  7. package/dist/911.astroviewer.cjs +4047 -0
  8. package/dist/911.astroviewer.cjs.map +1 -0
  9. package/dist/911.astroviewer.js +735 -0
  10. package/dist/911.astroviewer.js.map +1 -0
  11. package/dist/911.astroviewer.min.js +2 -0
  12. package/dist/911.astroviewer.min.js.map +1 -0
  13. package/dist/astroviewer.cjs +2704 -510
  14. package/dist/astroviewer.cjs.map +1 -1
  15. package/dist/astroviewer.js +2861 -512
  16. package/dist/astroviewer.js.map +1 -1
  17. package/dist/astroviewer.min.js +1 -1
  18. package/dist/astroviewer.min.js.map +1 -1
  19. package/lib-esm/AstroSphere.d.ts +1 -1
  20. package/lib-esm/AstroSphere.d.ts.map +1 -1
  21. package/lib-esm/AstroSphere.js +15 -25
  22. package/lib-esm/AstroSphere.js.map +1 -1
  23. package/lib-esm/AstroViewer.d.ts +25 -23
  24. package/lib-esm/AstroViewer.d.ts.map +1 -1
  25. package/lib-esm/AstroViewer.js +97 -67
  26. package/lib-esm/AstroViewer.js.map +1 -1
  27. package/lib-esm/model/hips/AllSky.d.ts +7 -3
  28. package/lib-esm/model/hips/AllSky.d.ts.map +1 -1
  29. package/lib-esm/model/hips/AllSky.js +93 -28
  30. package/lib-esm/model/hips/AllSky.js.map +1 -1
  31. package/lib-esm/model/hips/AncestorTile.d.ts +7 -4
  32. package/lib-esm/model/hips/AncestorTile.d.ts.map +1 -1
  33. package/lib-esm/model/hips/AncestorTile.js +91 -52
  34. package/lib-esm/model/hips/AncestorTile.js.map +1 -1
  35. package/lib-esm/model/hips/FitsTileLoader.d.ts +9 -0
  36. package/lib-esm/model/hips/FitsTileLoader.d.ts.map +1 -0
  37. package/lib-esm/model/hips/FitsTileLoader.js +65 -0
  38. package/lib-esm/model/hips/FitsTileLoader.js.map +1 -0
  39. package/lib-esm/model/hips/HiPS.d.ts +9 -5
  40. package/lib-esm/model/hips/HiPS.d.ts.map +1 -1
  41. package/lib-esm/model/hips/HiPS.js +120 -72
  42. package/lib-esm/model/hips/HiPS.js.map +1 -1
  43. package/lib-esm/model/hips/HiPSCoverage.d.ts +15 -0
  44. package/lib-esm/model/hips/HiPSCoverage.d.ts.map +1 -0
  45. package/lib-esm/model/hips/HiPSCoverage.js +148 -0
  46. package/lib-esm/model/hips/HiPSCoverage.js.map +1 -0
  47. package/lib-esm/model/hips/Tile.d.ts +8 -4
  48. package/lib-esm/model/hips/Tile.d.ts.map +1 -1
  49. package/lib-esm/model/hips/Tile.js +111 -55
  50. package/lib-esm/model/hips/Tile.js.map +1 -1
  51. package/lib-esm/model/hips/TileBuffer.d.ts +13 -4
  52. package/lib-esm/model/hips/TileBuffer.d.ts.map +1 -1
  53. package/lib-esm/model/hips/TileBuffer.js +46 -11
  54. package/lib-esm/model/hips/TileBuffer.js.map +1 -1
  55. package/lib-esm/model/hips/VisibleTilesManager.d.ts +5 -5
  56. package/lib-esm/model/hips/VisibleTilesManager.d.ts.map +1 -1
  57. package/lib-esm/model/hips/VisibleTilesManager.js +6 -20
  58. package/lib-esm/model/hips/VisibleTilesManager.js.map +1 -1
  59. package/lib-esm/shader/HiPSShaderProgram.d.ts +9 -2
  60. package/lib-esm/shader/HiPSShaderProgram.d.ts.map +1 -1
  61. package/lib-esm/shader/HiPSShaderProgram.js +91 -53
  62. package/lib-esm/shader/HiPSShaderProgram.js.map +1 -1
  63. package/lib-esm/shader/ShaderManager.d.ts +2 -0
  64. package/lib-esm/shader/ShaderManager.d.ts.map +1 -1
  65. package/lib-esm/shader/ShaderManager.js +193 -94
  66. package/lib-esm/shader/ShaderManager.js.map +1 -1
  67. package/package.json +3 -3
@@ -3980,9 +3980,15 @@ class AstroSphere {
3980
3980
  document.body.style.cursor = "grab";
3981
3981
  const dragDirection = Global_js_1.default.insideSphere ? -1 : 1;
3982
3982
  const dragSpeed = Global_js_1.default.insideSphere ? 10.0 : 1;
3983
- const deltaX = (dragDirection * dragSpeed * (newX - (this.lastMouseX ?? newX)) * Math.PI) /
3983
+ const deltaX = (dragDirection *
3984
+ dragSpeed *
3985
+ (newX - (this.lastMouseX ?? newX)) *
3986
+ Math.PI) /
3984
3987
  canvas.width;
3985
- const deltaY = (dragDirection * dragSpeed * (newY - (this.lastMouseY ?? newY)) * Math.PI) /
3988
+ const deltaY = (dragDirection *
3989
+ dragSpeed *
3990
+ (newY - (this.lastMouseY ?? newY)) *
3991
+ Math.PI) /
3986
3992
  canvas.height;
3987
3993
  const filteredDelta = this.filterRotationDeltaByAstroLocks(deltaX, deltaY);
3988
3994
  this.inertiaX += 0.1 * filteredDelta.deltaX;
@@ -4117,24 +4123,16 @@ class AstroSphere {
4117
4123
  const pickerPoint = RayPickingUtils_js_1.default.getIntersectionPointWithSingleModel(maxX / 2, maxY / 2, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
4118
4124
  return (0, Utils_js_1.cartesianToSpherical)(pickerPoint);
4119
4125
  }
4120
- collectViewportSphericalSamples(sampleCount = 5) {
4121
- const rect = this.canvas.getBoundingClientRect();
4122
- const width = rect.width;
4123
- const height = rect.height;
4124
- const samples = [];
4125
- for (let ix = 0; ix < sampleCount; ix++) {
4126
- const x = sampleCount === 1 ? width / 2 : (ix / (sampleCount - 1)) * width;
4127
- for (let iy = 0; iy < sampleCount; iy++) {
4128
- const y = sampleCount === 1 ? height / 2 : (iy / (sampleCount - 1)) * height;
4129
- const hit = RayPickingUtils_js_1.default.getIntersectionPointWithSingleModel(x, y, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
4130
- if (hit && hit.length > 0) {
4131
- samples.push((0, Utils_js_1.cartesianToSpherical)(hit));
4132
- }
4133
- }
4126
+ changeHiPSFormat(format) {
4127
+ if (!this._activeHiPS) {
4128
+ throw new Error("No active HiPS.");
4134
4129
  }
4135
- return samples;
4130
+ this._activeHiPS.changeFormat(format);
4136
4131
  }
4137
4132
  activateHiPS(hipsDescriptor) {
4133
+ if (this._activeHiPS) {
4134
+ this._healpixGrid.visibleTilesManager.tileBuffer.removeHiPS(this._activeHiPS);
4135
+ }
4138
4136
  this._activeHiPS = new HiPS_js_1.HiPS(1, [0.0, 0.0, 0.0], 0, 0, hipsDescriptor, this._webgl, this._healpixGrid);
4139
4137
  this._activeBaseLayer = "hips";
4140
4138
  }
@@ -4544,14 +4542,6 @@ class AstroSphere {
4544
4542
  Math.abs(this.inertiaX) > 0.02 ||
4545
4543
  Math.abs(this.inertiaY) > 0.02 ||
4546
4544
  nowForGrid - this.lastCameraMotionAt < 220;
4547
- // const skyEntityDrawInput: SkyEntityDrawInput = {
4548
- // fovDeg: this._healpixGrid.getMinFoV(),
4549
- // camera: this._camera,
4550
- // pMatrix: this._perspectiveMatrixManager.pMatrix,
4551
- // centerSphericalDeg: this.updateCentralPoint().sphericalDeg,
4552
- // fovPolygon: this._activeBaseLayer === 'xyz' ? this.getFoVPolygon() : undefined,
4553
- // viewportSphericalSamples: this._activeBaseLayer === 'xyz' ? this.collectViewportSphericalSamples(7) : undefined,
4554
- // }
4555
4545
  const skyEntityDrawInput = {
4556
4546
  fovDeg: stableFovDeg,
4557
4547
  camera: this._camera,
@@ -4703,7 +4693,7 @@ class AstroViewer {
4703
4693
  webglContextList = new Map();
4704
4694
  viewfinderEl = null;
4705
4695
  viewfinderVisible = Config_js_1.bootSetup.showViewfinder;
4706
- viewfinderColor = 'rgba(75,148,226,0.68)';
4696
+ viewfinderColor = "rgba(75,148,226,0.68)";
4707
4697
  options = {};
4708
4698
  // API
4709
4699
  run() {
@@ -4841,7 +4831,7 @@ class AstroViewer {
4841
4831
  this.astroSphere.activateXYZ(config);
4842
4832
  }
4843
4833
  activateXYZ2(config) {
4844
- const descriptor = new XYZMapDescriptor_js_1.XYZMapDescriptor(config.name ?? 'XYZ Earth2 Layer', config.urlTemplate, config.minZoom ?? 0, config.maxZoom ?? 8, config.segmentsPerSide ?? 48, config.maxCachedTiles ?? 384, 8, config.urlResolver);
4834
+ const descriptor = new XYZMapDescriptor_js_1.XYZMapDescriptor(config.name ?? "XYZ Earth2 Layer", config.urlTemplate, config.minZoom ?? 0, config.maxZoom ?? 8, config.segmentsPerSide ?? 48, config.maxCachedTiles ?? 384, 8, config.urlResolver);
4845
4835
  this.astroSphere.activateXYZ2(descriptor);
4846
4836
  }
4847
4837
  activateWMTS(config) {
@@ -4866,8 +4856,8 @@ class AstroViewer {
4866
4856
  return this.astroSphere.getMeshHiPSDebugStats();
4867
4857
  }
4868
4858
  async loadHiPS(baseUrl) {
4869
- const hipsUrl = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
4870
- const resp = await fetch(hipsUrl + 'properties');
4859
+ const hipsUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
4860
+ const resp = await fetch(hipsUrl + "properties");
4871
4861
  if (!resp.ok)
4872
4862
  throw new Error(`HTTP ${resp.status} fetching properties`);
4873
4863
  const propsText = await resp.text();
@@ -4877,20 +4867,20 @@ class AstroViewer {
4877
4867
  // this.activateHiPS(desc);
4878
4868
  }
4879
4869
  async loadMeshHiPS(baseUrl, config = {}) {
4880
- const meshHiPSUrl = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
4881
- let propsText = '';
4882
- const resp = await fetch(meshHiPSUrl + 'properties');
4870
+ const meshHiPSUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
4871
+ let propsText = "";
4872
+ const resp = await fetch(meshHiPSUrl + "properties");
4883
4873
  if (resp.ok) {
4884
4874
  propsText = await resp.text();
4885
4875
  }
4886
4876
  else {
4887
- const jsonResp = await fetch(meshHiPSUrl + 'properties.json');
4877
+ const jsonResp = await fetch(meshHiPSUrl + "properties.json");
4888
4878
  if (!jsonResp.ok)
4889
4879
  throw new Error(`HTTP ${jsonResp.status} fetching MeshHiPS properties`);
4890
4880
  const json = await jsonResp.json();
4891
4881
  propsText = Object.entries(json)
4892
4882
  .map(([key, value]) => `${key}=${String(value)}`)
4893
- .join('\n');
4883
+ .join("\n");
4894
4884
  }
4895
4885
  const desc = new MeshHiPSDescriptor_js_1.MeshHiPSDescriptor({ ...config, baseUrl: meshHiPSUrl }, propsText);
4896
4886
  this.astroSphere.activateMeshHiPS(desc);
@@ -4908,6 +4898,12 @@ class AstroViewer {
4908
4898
  getActiveHiPS() {
4909
4899
  return this.astroSphere.activeHiPS;
4910
4900
  }
4901
+ changeHiPSFormat(format) {
4902
+ this.astroSphere.changeHiPSFormat(format);
4903
+ }
4904
+ getActiveHiPSFormats() {
4905
+ return this.astroSphere.activeHiPS?.availableFormats ?? [];
4906
+ }
4911
4907
  getActiveXYZ() {
4912
4908
  return this.astroSphere.activeXYZ;
4913
4909
  }
@@ -4995,13 +4991,13 @@ class AstroViewer {
4995
4991
  return this.astroSphere.getFoVPolygon();
4996
4992
  }
4997
4993
  changeFoV(deg) {
4998
- this, this.astroSphere.changeFoV(deg);
4994
+ (this, this.astroSphere.changeFoV(deg));
4999
4995
  }
5000
4996
  changeFoV2(deg) {
5001
- this, this.astroSphere.changeFoV2(deg);
4997
+ (this, this.astroSphere.changeFoV2(deg));
5002
4998
  }
5003
4999
  changeFoV3(deg) {
5004
- this, this.astroSphere.changeFoV3(deg);
5000
+ (this, this.astroSphere.changeFoV3(deg));
5005
5001
  }
5006
5002
  getInsideSphere() {
5007
5003
  return this.astroSphere.getInsideSphere();
@@ -5047,13 +5043,13 @@ class AstroViewer {
5047
5043
  this.webglContextList = new Map();
5048
5044
  }
5049
5045
  init(canvasEl) {
5050
- console.log('init webgl');
5046
+ console.log("init webgl");
5051
5047
  this.canvas = canvasEl;
5052
5048
  this.initViewfinder();
5053
- const gl = this.canvas.getContext('webgl2', { alpha: false });
5049
+ const gl = this.canvas.getContext("webgl2", { alpha: false });
5054
5050
  if (!gl) {
5055
- alert('Could not initialise WebGL, sorry :-(');
5056
- throw new Error('WebGL2 not available');
5051
+ alert("Could not initialise WebGL, sorry :-(");
5052
+ throw new Error("WebGL2 not available");
5057
5053
  }
5058
5054
  // Extend with custom fields used elsewhere
5059
5055
  this.webgl = gl;
@@ -5064,7 +5060,7 @@ class AstroViewer {
5064
5060
  this.webgl.clearColor(0 * 0.00392156862, 16 * 0.00392156862, 50 * 0.00392156862, 0.7);
5065
5061
  }
5066
5062
  catch (e) {
5067
- console.log('Error instantiating WebGL context');
5063
+ console.log("Error instantiating WebGL context");
5068
5064
  }
5069
5065
  this.initListeners();
5070
5066
  // ; (global as any).gl = this.webgl
@@ -5076,40 +5072,64 @@ class AstroViewer {
5076
5072
  const parent = this.canvas.parentElement;
5077
5073
  if (!parent)
5078
5074
  return;
5079
- if (window.getComputedStyle(parent).position === 'static') {
5080
- parent.style.position = 'relative';
5081
- }
5082
- const viewfinder = document.createElement('div');
5083
- viewfinder.setAttribute('data-astro-viewfinder', 'true');
5084
- viewfinder.setAttribute('aria-hidden', 'true');
5085
- viewfinder.style.position = 'absolute';
5086
- viewfinder.style.left = '50%';
5087
- viewfinder.style.top = '50%';
5088
- viewfinder.style.width = '44px';
5089
- viewfinder.style.height = '44px';
5090
- viewfinder.style.transform = 'translate(-50%, -50%)';
5091
- viewfinder.style.pointerEvents = 'none';
5092
- viewfinder.style.zIndex = '1';
5093
- viewfinder.style.boxSizing = 'border-box';
5075
+ if (window.getComputedStyle(parent).position === "static") {
5076
+ parent.style.position = "relative";
5077
+ }
5078
+ const viewfinder = document.createElement("div");
5079
+ viewfinder.setAttribute("data-astro-viewfinder", "true");
5080
+ viewfinder.setAttribute("aria-hidden", "true");
5081
+ viewfinder.style.position = "absolute";
5082
+ viewfinder.style.left = "50%";
5083
+ viewfinder.style.top = "50%";
5084
+ viewfinder.style.width = "44px";
5085
+ viewfinder.style.height = "44px";
5086
+ viewfinder.style.transform = "translate(-50%, -50%)";
5087
+ viewfinder.style.pointerEvents = "none";
5088
+ viewfinder.style.zIndex = "1";
5089
+ viewfinder.style.boxSizing = "border-box";
5094
5090
  const segments = [
5095
- { left: '50%', top: '7px', width: '1px', height: '11px', transform: 'translateX(-50%)' },
5096
- { left: '50%', bottom: '7px', width: '1px', height: '11px', transform: 'translateX(-50%)' },
5097
- { left: '7px', top: '50%', width: '11px', height: '1px', transform: 'translateY(-50%)' },
5098
- { right: '7px', top: '50%', width: '11px', height: '1px', transform: 'translateY(-50%)' },
5091
+ {
5092
+ left: "50%",
5093
+ top: "7px",
5094
+ width: "1px",
5095
+ height: "11px",
5096
+ transform: "translateX(-50%)",
5097
+ },
5098
+ {
5099
+ left: "50%",
5100
+ bottom: "7px",
5101
+ width: "1px",
5102
+ height: "11px",
5103
+ transform: "translateX(-50%)",
5104
+ },
5105
+ {
5106
+ left: "7px",
5107
+ top: "50%",
5108
+ width: "11px",
5109
+ height: "1px",
5110
+ transform: "translateY(-50%)",
5111
+ },
5112
+ {
5113
+ right: "7px",
5114
+ top: "50%",
5115
+ width: "11px",
5116
+ height: "1px",
5117
+ transform: "translateY(-50%)",
5118
+ },
5099
5119
  ];
5100
5120
  for (const segmentDef of segments) {
5101
- const segment = document.createElement('div');
5102
- segment.style.position = 'absolute';
5103
- segment.style.left = segmentDef.left ?? 'auto';
5104
- segment.style.right = segmentDef.right ?? 'auto';
5105
- segment.style.top = segmentDef.top ?? 'auto';
5106
- segment.style.bottom = segmentDef.bottom ?? 'auto';
5121
+ const segment = document.createElement("div");
5122
+ segment.style.position = "absolute";
5123
+ segment.style.left = segmentDef.left ?? "auto";
5124
+ segment.style.right = segmentDef.right ?? "auto";
5125
+ segment.style.top = segmentDef.top ?? "auto";
5126
+ segment.style.bottom = segmentDef.bottom ?? "auto";
5107
5127
  segment.style.width = segmentDef.width;
5108
5128
  segment.style.height = segmentDef.height;
5109
5129
  segment.style.transform = segmentDef.transform;
5110
- segment.style.background = 'currentColor';
5111
- segment.style.borderRadius = '999px';
5112
- segment.style.boxShadow = '0 0 0 1px rgba(0, 0, 0, 0.14)';
5130
+ segment.style.background = "currentColor";
5131
+ segment.style.borderRadius = "999px";
5132
+ segment.style.boxShadow = "0 0 0 1px rgba(0, 0, 0, 0.14)";
5113
5133
  viewfinder.appendChild(segment);
5114
5134
  }
5115
5135
  parent.appendChild(viewfinder);
@@ -5120,7 +5140,7 @@ class AstroViewer {
5120
5140
  syncViewfinderVisibility() {
5121
5141
  if (!this.viewfinderEl)
5122
5142
  return;
5123
- this.viewfinderEl.style.display = this.viewfinderVisible ? 'block' : 'none';
5143
+ this.viewfinderEl.style.display = this.viewfinderVisible ? "block" : "none";
5124
5144
  }
5125
5145
  syncViewfinderColor() {
5126
5146
  if (!this.viewfinderEl)
@@ -5128,9 +5148,9 @@ class AstroViewer {
5128
5148
  this.viewfinderEl.style.color = this.viewfinderColor;
5129
5149
  }
5130
5150
  initListeners() {
5131
- console.log('inside initListeners');
5151
+ console.log("inside initListeners");
5132
5152
  const resizeCanvas = () => {
5133
- console.log('[resizeCanvas]');
5153
+ console.log("[resizeCanvas]");
5134
5154
  const rect = this.canvas.getBoundingClientRect();
5135
5155
  const dpr = window.devicePixelRatio || 1;
5136
5156
  const newWidth = Math.max(1, Math.floor(rect.width * dpr));
@@ -5144,7 +5164,7 @@ class AstroViewer {
5144
5164
  }
5145
5165
  };
5146
5166
  const handleContextLost = (event) => {
5147
- console.log('[handleContextLost]');
5167
+ console.log("[handleContextLost]");
5148
5168
  event.preventDefault();
5149
5169
  if (this.rafId !== null) {
5150
5170
  cancelAnimationFrame(this.rafId);
@@ -5152,7 +5172,7 @@ class AstroViewer {
5152
5172
  }
5153
5173
  };
5154
5174
  const handleContextRestored = (_event) => {
5155
- console.log('[handleContextRestored]');
5175
+ console.log("[handleContextRestored]");
5156
5176
  // this.webgl.viewportWidth = this.canvas.width
5157
5177
  // this.webgl.viewportHeight = this.canvas.height
5158
5178
  this.webgl.clearColor(0 * 0.00392156862, 16 * 0.00392156862, 50 * 0.00392156862, 0.7);
@@ -5160,16 +5180,16 @@ class AstroViewer {
5160
5180
  this.rafId = requestAnimationFrame(() => this.tick());
5161
5181
  };
5162
5182
  // 🔥 ResizeObserver per pannelli / split / layout dinamici
5163
- if ('ResizeObserver' in window) {
5183
+ if ("ResizeObserver" in window) {
5164
5184
  const ro = new ResizeObserver(() => {
5165
5185
  resizeCanvas();
5166
5186
  });
5167
5187
  // Osserva il canvas o il suo parent (a tua scelta)
5168
5188
  ro.observe(this.canvas);
5169
5189
  }
5170
- window.addEventListener('resize', resizeCanvas);
5171
- this.canvas.addEventListener('webglcontextlost', handleContextLost, false);
5172
- this.canvas.addEventListener('webglcontextrestored', handleContextRestored, false);
5190
+ window.addEventListener("resize", resizeCanvas);
5191
+ this.canvas.addEventListener("webglcontextlost", handleContextLost, false);
5192
+ this.canvas.addEventListener("webglcontextrestored", handleContextRestored, false);
5173
5193
  resizeCanvas();
5174
5194
  }
5175
5195
  tick() {
@@ -11887,6 +11907,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11887
11907
  };
11888
11908
  Object.defineProperty(exports, "__esModule", ({ value: true }));
11889
11909
  const Global_js_1 = __importDefault(__webpack_require__(4382));
11910
+ const FitsTileLoader_js_1 = __webpack_require__(1399);
11890
11911
  class AllSky {
11891
11912
  _ready = false;
11892
11913
  _hips;
@@ -11899,6 +11920,7 @@ class AllSky {
11899
11920
  _texture = null;
11900
11921
  _image;
11901
11922
  _texurl;
11923
+ _fitsTile;
11902
11924
  _textureLoaded = false;
11903
11925
  _maxTiles = 0;
11904
11926
  _numFacesXTile = 0;
@@ -11921,15 +11943,34 @@ class AllSky {
11921
11943
  this.initImage();
11922
11944
  }
11923
11945
  initImage() {
11924
- this._image = new Image();
11925
11946
  this._texurl = `${this._baseurl}/Norder3/Allsky.${this._format}`;
11947
+ if (this._format === "fits") {
11948
+ void this.loadFits();
11949
+ return;
11950
+ }
11951
+ this.loadImage();
11952
+ }
11953
+ loadImage() {
11954
+ this._image = new Image();
11926
11955
  this._image.onload = () => this.imageLoaded();
11927
11956
  this._image.onerror = () => {
11928
- console.error('File not found? %s', this._texurl);
11957
+ console.error("File not found? %s", this._texurl);
11929
11958
  };
11930
- this._image.setAttribute('crossorigin', 'anonymous');
11959
+ this._image.setAttribute("crossorigin", "anonymous");
11931
11960
  this._image.src = this._texurl;
11932
11961
  }
11962
+ async loadFits() {
11963
+ try {
11964
+ this._fitsTile = await (0, FitsTileLoader_js_1.loadFitsTile)(this._texurl);
11965
+ this.textureLoaded();
11966
+ this.initModelBuffer();
11967
+ this._textureLoaded = true;
11968
+ this._ready = true;
11969
+ }
11970
+ catch (error) {
11971
+ console.error(`[AllSky] Unable to load FITS atlas ${this._texurl}`, error);
11972
+ }
11973
+ }
11933
11974
  imageLoaded() {
11934
11975
  this.textureLoaded();
11935
11976
  this.initModelBuffer();
@@ -11937,31 +11978,58 @@ class AllSky {
11937
11978
  this._ready = true;
11938
11979
  }
11939
11980
  textureLoaded() {
11940
- // hipsShaderProgram.enableProgram()
11941
11981
  this._hipsShaderProgram.enableProgram();
11942
11982
  const gl = this._webgl;
11943
11983
  this._texture = gl.createTexture();
11944
11984
  gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
11945
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
11985
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this._format !== "fits");
11946
11986
  gl.bindTexture(gl.TEXTURE_2D, this._texture);
11947
- // gl.uniform1i(hipsShaderProgram.shaderProgram.samplerUniform, this._hipsShaderIndex)
11948
- if (!gl.isTexture(this._texture)) {
11949
- console.log('error in texture');
11987
+ if (this._format === "fits") {
11988
+ const fits = this._fitsTile;
11989
+ if (!fits) {
11990
+ throw new Error(`FITS AllSky data not loaded: ${this._texurl}`);
11991
+ }
11992
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, fits.width, fits.height, 0, gl.RED, gl.FLOAT, fits.pixels);
11993
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
11994
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
11995
+ }
11996
+ else {
11997
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
11998
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
11999
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
12000
+ gl.generateMipmap(gl.TEXTURE_2D);
11950
12001
  }
11951
- gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
11952
- gl.bindTexture(gl.TEXTURE_2D, this._texture);
11953
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
11954
12002
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
11955
12003
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
11956
- const useMipmaps = true;
11957
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, useMipmaps ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
11958
- // MAG filter: ONLY NEAREST or LINEAR are valid
11959
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
11960
- // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
11961
- // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR_MIPMAP_LINEAR)
11962
- // gl.generateMipmap(gl.TEXTURE_2D)
11963
- if (useMipmaps)
11964
- gl.generateMipmap(gl.TEXTURE_2D);
12004
+ if (!gl.isTexture(this._texture)) {
12005
+ console.log("error in texture");
12006
+ }
12007
+ }
12008
+ getFitsDataRange() {
12009
+ const hipsRange = this._hips.dataRange;
12010
+ if (hipsRange.min !== undefined &&
12011
+ hipsRange.max !== undefined &&
12012
+ Number.isFinite(hipsRange.min) &&
12013
+ Number.isFinite(hipsRange.max) &&
12014
+ hipsRange.max > hipsRange.min) {
12015
+ return {
12016
+ min: hipsRange.min,
12017
+ max: hipsRange.max,
12018
+ };
12019
+ }
12020
+ const fits = this._fitsTile;
12021
+ if (fits &&
12022
+ fits.dataMin !== null &&
12023
+ fits.dataMax !== null &&
12024
+ Number.isFinite(fits.dataMin) &&
12025
+ Number.isFinite(fits.dataMax) &&
12026
+ fits.dataMax > fits.dataMin) {
12027
+ return {
12028
+ min: fits.dataMin,
12029
+ max: fits.dataMax,
12030
+ };
12031
+ }
12032
+ return null;
11965
12033
  }
11966
12034
  initModelBuffer() {
11967
12035
  const gl = this._webgl;
@@ -12026,13 +12094,16 @@ class AllSky {
12026
12094
  this.vertexPosition[20 * this.vidx] = facesVec3Array[0].x;
12027
12095
  this.vertexPosition[20 * this.vidx + 1] = facesVec3Array[0].y;
12028
12096
  this.vertexPosition[20 * this.vidx + 2] = facesVec3Array[0].z;
12029
- this.vertexPosition[20 * this.vidx + 3] = s_step + base_s - s_pixel_size;
12030
- this.vertexPosition[20 * this.vidx + 4] = 1 - (t_step + base_t) + t_pixel_size;
12097
+ this.vertexPosition[20 * this.vidx + 3] =
12098
+ s_step + base_s - s_pixel_size;
12099
+ this.vertexPosition[20 * this.vidx + 4] =
12100
+ 1 - (t_step + base_t) + t_pixel_size;
12031
12101
  // top right
12032
12102
  this.vertexPosition[20 * this.vidx + 5] = facesVec3Array[1].x;
12033
12103
  this.vertexPosition[20 * this.vidx + 6] = facesVec3Array[1].y;
12034
12104
  this.vertexPosition[20 * this.vidx + 7] = facesVec3Array[1].z;
12035
- this.vertexPosition[20 * this.vidx + 8] = s_step + base_s - s_pixel_size;
12105
+ this.vertexPosition[20 * this.vidx + 8] =
12106
+ s_step + base_s - s_pixel_size;
12036
12107
  this.vertexPosition[20 * this.vidx + 9] = 1 - base_t - t_pixel_size;
12037
12108
  // top left
12038
12109
  this.vertexPosition[20 * this.vidx + 10] = facesVec3Array[2].x;
@@ -12045,7 +12116,8 @@ class AllSky {
12045
12116
  this.vertexPosition[20 * this.vidx + 16] = facesVec3Array[3].y;
12046
12117
  this.vertexPosition[20 * this.vidx + 17] = facesVec3Array[3].z;
12047
12118
  this.vertexPosition[20 * this.vidx + 18] = base_s + s_pixel_size;
12048
- this.vertexPosition[20 * this.vidx + 19] = 1 - (t_step + base_t) + t_pixel_size;
12119
+ this.vertexPosition[20 * this.vidx + 19] =
12120
+ 1 - (t_step + base_t) + t_pixel_size;
12049
12121
  this.vidx++;
12050
12122
  }
12051
12123
  }
@@ -12065,6 +12137,17 @@ class AllSky {
12065
12137
  }
12066
12138
  const gl = this._webgl;
12067
12139
  this._hipsShaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx);
12140
+ if (this._format === "fits") {
12141
+ const range = this.getFitsDataRange();
12142
+ if (!range) {
12143
+ console.error(`[AllSky] No display range available for FITS atlas ${this._texurl}`);
12144
+ return false;
12145
+ }
12146
+ this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max);
12147
+ }
12148
+ else {
12149
+ this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, false);
12150
+ }
12068
12151
  gl.enableVertexAttribArray(this._hipsShaderProgram.locations.vertexPositionAttribute);
12069
12152
  gl.enableVertexAttribArray(this._hipsShaderProgram.locations.textureCoordAttribute);
12070
12153
  // hipsShaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx)
@@ -12072,8 +12155,10 @@ class AllSky {
12072
12155
  // gl.enableVertexAttribArray((hipsShaderProgram as any).locations.textureCoordAttribute)
12073
12156
  gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
12074
12157
  gl.bindTexture(gl.TEXTURE_2D, this._texture);
12075
- // gl.uniform1f(hipsShaderProgram.locations.textureAlpha, this.opacity)
12076
- gl.uniform1f(this._hipsShaderProgram.locations.textureAlpha, this.opacity);
12158
+ const factorLocation = this._hipsShaderProgram.locations.textureAlpha[this._hipsShaderIndex];
12159
+ if (factorLocation) {
12160
+ gl.uniform1f(factorLocation, this.opacity);
12161
+ }
12077
12162
  gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBuffer);
12078
12163
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.vertexIndexBuffer);
12079
12164
  gl.vertexAttribPointer(
@@ -12141,6 +12226,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12141
12226
  Object.defineProperty(exports, "__esModule", ({ value: true }));
12142
12227
  const Global_js_1 = __importDefault(__webpack_require__(4382));
12143
12228
  const FoVHelper_js_1 = __webpack_require__(229);
12229
+ const FitsTileLoader_js_1 = __webpack_require__(1399);
12144
12230
  class AncestorTile {
12145
12231
  _hips;
12146
12232
  _tileno;
@@ -12154,7 +12240,8 @@ class AncestorTile {
12154
12240
  _pixels = [];
12155
12241
  _texture = null;
12156
12242
  _image;
12157
- _texurl = '';
12243
+ _texurl = "";
12244
+ _fitsTile;
12158
12245
  vertexPosition;
12159
12246
  vertexPositionBuffer;
12160
12247
  vertexIndices;
@@ -12180,14 +12267,41 @@ class AncestorTile {
12180
12267
  }
12181
12268
  initImage() {
12182
12269
  const dirnumber = Math.floor(this._tileno / 10000) * 10000;
12183
- this._texurl = `${this._baseurl}/Norder${this._order}/Dir${dirnumber}/Npix${this._tileno}.${this._format}`;
12270
+ this._texurl =
12271
+ `${this._baseurl}/Norder${this._order}/Dir${dirnumber}` +
12272
+ `/Npix${this._tileno}.${this._format}`;
12273
+ if (this._format === "fits") {
12274
+ void this.loadFits();
12275
+ return;
12276
+ }
12277
+ this.loadImage();
12278
+ }
12279
+ async loadFits() {
12280
+ try {
12281
+ this._fitsTile = await (0, FitsTileLoader_js_1.loadFitsTile)(this._texurl);
12282
+ this.textureLoaded();
12283
+ const fits = this._fitsTile;
12284
+ if (!fits) {
12285
+ throw new Error(`FITS tile data not loaded: ${this._texurl}`);
12286
+ }
12287
+ const gl = this._webgl;
12288
+ gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
12289
+ gl.bindTexture(gl.TEXTURE_2D, this._texture);
12290
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, fits.width, fits.height, 0, gl.RED, gl.FLOAT, fits.pixels);
12291
+ this.initModelBuffer();
12292
+ this._ready = true;
12293
+ }
12294
+ catch (error) {
12295
+ console.error(`[AncestorTile] Unable to load FITS tile ${this._texurl}`, error);
12296
+ }
12297
+ }
12298
+ loadImage() {
12184
12299
  this._image = new Image();
12185
12300
  this._image.onload = () => this.imageLoaded();
12186
12301
  this._image.onerror = () => {
12187
- console.error('File not found? %s', this._texurl);
12302
+ console.error("File not found? %s", this._texurl);
12188
12303
  };
12189
- this._image.crossOrigin = 'anonymous';
12190
- // If you ever need FITS handling, call this.loadImage() instead.
12304
+ this._image.crossOrigin = "anonymous";
12191
12305
  this._image.src = this._texurl;
12192
12306
  }
12193
12307
  imageLoaded() {
@@ -12205,15 +12319,47 @@ class AncestorTile {
12205
12319
  const gl = this._webgl;
12206
12320
  this._texture = gl.createTexture();
12207
12321
  gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
12208
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
12322
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this._format !== "fits");
12209
12323
  gl.bindTexture(gl.TEXTURE_2D, this._texture);
12210
12324
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
12211
12325
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
12212
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
12213
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
12326
+ if (this._format === "fits") {
12327
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
12328
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
12329
+ }
12330
+ else {
12331
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
12332
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
12333
+ }
12214
12334
  if (!gl.isTexture(this._texture)) {
12215
- console.log('error in texture');
12335
+ console.log("error in texture");
12336
+ }
12337
+ }
12338
+ getFitsDataRange() {
12339
+ const hipsRange = this._hips.dataRange;
12340
+ if (hipsRange.min !== undefined &&
12341
+ hipsRange.max !== undefined &&
12342
+ Number.isFinite(hipsRange.min) &&
12343
+ Number.isFinite(hipsRange.max) &&
12344
+ hipsRange.max > hipsRange.min) {
12345
+ return {
12346
+ min: hipsRange.min,
12347
+ max: hipsRange.max,
12348
+ };
12349
+ }
12350
+ const fits = this._fitsTile;
12351
+ if (fits &&
12352
+ fits.dataMin !== null &&
12353
+ fits.dataMax !== null &&
12354
+ Number.isFinite(fits.dataMin) &&
12355
+ Number.isFinite(fits.dataMax) &&
12356
+ fits.dataMax > fits.dataMin) {
12357
+ return {
12358
+ min: fits.dataMin,
12359
+ max: fits.dataMax,
12360
+ };
12216
12361
  }
12362
+ return null;
12217
12363
  }
12218
12364
  initModelBuffer() {
12219
12365
  const gl = this._webgl;
@@ -12256,43 +12402,6 @@ class AncestorTile {
12256
12402
  }
12257
12403
  return vertexIndices;
12258
12404
  }
12259
- // Version that uses getPointsForXyfNoStep (kept for reference; not used in this class)
12260
- setupPositionAndTexture4Quadrant2(dxmin, dxmax, dymin, dymax, qidx, healpix, orderjump, origxyf) {
12261
- this.vertexPosition[qidx] = new Float32Array(20 * (dxmax - dxmin) * (dymax - dymin));
12262
- const step = 1 / (1 << orderjump);
12263
- let p = 0;
12264
- for (let dx = dxmin; dx < dxmax; dx++) {
12265
- for (let dy = dymin; dy < dymax; dy++) {
12266
- const facesVec3Array = healpix.getPointsForXyfNoStep(dx, dy, origxyf.face);
12267
- const uindex = dy - (origxyf.iy << orderjump);
12268
- const vindex = dx - (origxyf.ix << orderjump);
12269
- this.vertexPosition[qidx][20 * p] = facesVec3Array[0].x;
12270
- this.vertexPosition[qidx][20 * p + 1] = facesVec3Array[0].y;
12271
- this.vertexPosition[qidx][20 * p + 2] = facesVec3Array[0].z;
12272
- this.vertexPosition[qidx][20 * p + 3] = step + step * uindex;
12273
- this.vertexPosition[qidx][20 * p + 4] = 1 - (step + step * vindex);
12274
- this.vertexPosition[qidx][20 * p + 5] = facesVec3Array[1].x;
12275
- this.vertexPosition[qidx][20 * p + 6] = facesVec3Array[1].y;
12276
- this.vertexPosition[qidx][20 * p + 7] = facesVec3Array[1].z;
12277
- this.vertexPosition[qidx][20 * p + 8] = step + step * uindex;
12278
- this.vertexPosition[qidx][20 * p + 9] = 1 - step * vindex;
12279
- this.vertexPosition[qidx][20 * p + 10] = facesVec3Array[2].x;
12280
- this.vertexPosition[qidx][20 * p + 11] = facesVec3Array[2].y;
12281
- this.vertexPosition[qidx][20 * p + 12] = facesVec3Array[2].z;
12282
- this.vertexPosition[qidx][20 * p + 13] = step * uindex;
12283
- this.vertexPosition[qidx][20 * p + 14] = 1 - step * vindex;
12284
- this.vertexPosition[qidx][20 * p + 15] = facesVec3Array[3].x;
12285
- this.vertexPosition[qidx][20 * p + 16] = facesVec3Array[3].y;
12286
- this.vertexPosition[qidx][20 * p + 17] = facesVec3Array[3].z;
12287
- this.vertexPosition[qidx][20 * p + 18] = step * uindex;
12288
- this.vertexPosition[qidx][20 * p + 19] = 1 - (step + step * vindex);
12289
- p++;
12290
- }
12291
- }
12292
- this.vertexPositionBuffer[qidx] = this._webgl.createBuffer();
12293
- this._webgl.bindBuffer(this._webgl.ARRAY_BUFFER, this.vertexPositionBuffer[qidx]);
12294
- this._webgl.bufferData(this._webgl.ARRAY_BUFFER, this.vertexPosition[qidx], this._webgl.STATIC_DRAW);
12295
- }
12296
12405
  // Version used by the original JS, collecting _pixels via xyf2nest + getBoundaries
12297
12406
  setupPositionAndTexture4Quadrant(dxmin, dxmax, dymin, dymax, qidx, healpix, orderjump, origxyf) {
12298
12407
  const gl = this._webgl;
@@ -12344,12 +12453,26 @@ class AncestorTile {
12344
12453
  quadrantsToDraw = q;
12345
12454
  }
12346
12455
  this._hipsShaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx);
12456
+ if (this._format === "fits") {
12457
+ const range = this.getFitsDataRange();
12458
+ if (!range) {
12459
+ console.error(`[AncestorTile] No display range available for FITS tile ${this._texurl}`);
12460
+ return false;
12461
+ }
12462
+ this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max);
12463
+ }
12464
+ else {
12465
+ this._hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, false);
12466
+ }
12347
12467
  const gl = this._webgl;
12348
12468
  gl.enableVertexAttribArray(this._hipsShaderProgram.locations.vertexPositionAttribute);
12349
12469
  gl.enableVertexAttribArray(this._hipsShaderProgram.locations.textureCoordAttribute);
12350
12470
  gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
12351
12471
  gl.bindTexture(gl.TEXTURE_2D, this._texture);
12352
- gl.uniform1f(this._hipsShaderProgram.locations.textureAlpha, this.opacity);
12472
+ const factorLocation = this._hipsShaderProgram.locations.textureAlpha[this._hipsShaderIndex];
12473
+ if (factorLocation) {
12474
+ gl.uniform1f(factorLocation, this.opacity);
12475
+ }
12353
12476
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.vertexIndexBuffer);
12354
12477
  const elemno = this.vertexIndices.length;
12355
12478
  quadrantsToDraw.forEach((qidx) => {
@@ -12376,8 +12499,9 @@ class AncestorTile {
12376
12499
  : this._tileBuffer.getTile(childTileNo, childrenOrder, this._hips);
12377
12500
  // childTile.draw(visibleOrder, visibleTilesMap, pMatrix, vMatrix, mMatrix, colorMapIdx)
12378
12501
  childTile.draw(visibleOrder, visibleTilesMap, pMatrix, vMatrix, mMatrix, colorMapIdx, this._hipsShaderProgram);
12379
- if (childTile._ready) {
12380
- quadrantsToDraw.delete(childTile._tileno - (this._tileno << 2));
12502
+ if (childTile.getReadyState()) {
12503
+ quadrantsToDraw.delete(c);
12504
+ // quadrantsToDraw.delete((childTile as any)._tileno - (this._tileno << 2))
12381
12505
  }
12382
12506
  }
12383
12507
  }
@@ -12387,6 +12511,81 @@ class AncestorTile {
12387
12511
  exports["default"] = AncestorTile;
12388
12512
 
12389
12513
 
12514
+ /***/ },
12515
+
12516
+ /***/ 1399
12517
+ (__unused_webpack_module, exports, __webpack_require__) {
12518
+
12519
+ var __webpack_unused_export__;
12520
+
12521
+ /*
12522
+ * AstroViewer
12523
+ * Copyright (C) Fabrizio Giordano
12524
+ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-AstroViewer-Commercial
12525
+ *
12526
+ * AstroViewer is dual-licensed under the GNU Affero General Public License
12527
+ * version 3 and a separate commercial license.
12528
+ *
12529
+ * See LICENSE.md, LICENSE-AGPL.md, and LICENSE-COMMERCIAL.md for details.
12530
+ */
12531
+ __webpack_unused_export__ = ({ value: true });
12532
+ exports.loadFitsTile = loadFitsTile;
12533
+ const jsfitsio_1 = __webpack_require__(4971);
12534
+ async function loadFitsTile(url) {
12535
+ const fitsFile = await jsfitsio_1.FITSParser.loadFITSFile(url);
12536
+ if (!fitsFile?.primaryHDU) {
12537
+ throw new Error(`Unable to load FITS tile: ${url}`);
12538
+ }
12539
+ const image = fitsFile.primaryHDU;
12540
+ if (image.naxis !== 2) {
12541
+ throw new Error(`Expected a 2D FITS tile, got NAXIS=${image.naxis}: ${url}`);
12542
+ }
12543
+ const [width, height] = image.shape;
12544
+ if (!Number.isInteger(width) ||
12545
+ !Number.isInteger(height) ||
12546
+ width <= 0 ||
12547
+ height <= 0) {
12548
+ throw new Error(`Invalid FITS tile dimensions: ${url}`);
12549
+ }
12550
+ const data = image.typedData;
12551
+ if (!data || data.length !== width * height) {
12552
+ throw new Error(`Invalid FITS tile payload: ${url}`);
12553
+ }
12554
+ if (data instanceof BigInt64Array) {
12555
+ throw new Error(`BITPIX=64 FITS tiles are not supported for HiPS rendering: ${url}`);
12556
+ }
12557
+ const bscale = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.BSCALE) ?? 1;
12558
+ const bzero = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.BZERO) ?? 0;
12559
+ const blank = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.BLANK);
12560
+ const dataMin = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.DATAMIN);
12561
+ const dataMax = getNumericHeaderValue(image.header, jsfitsio_1.FITSHeaderManager.DATAMAX);
12562
+ const pixels = new Float32Array(data.length);
12563
+ for (let i = 0; i < data.length; i++) {
12564
+ const rawValue = data[i];
12565
+ if (!Number.isFinite(rawValue) || (blank !== null && rawValue === blank)) {
12566
+ pixels[i] = Number.NaN;
12567
+ continue;
12568
+ }
12569
+ pixels[i] = rawValue * bscale + bzero;
12570
+ }
12571
+ return {
12572
+ width,
12573
+ height,
12574
+ pixels,
12575
+ dataMin,
12576
+ dataMax,
12577
+ };
12578
+ }
12579
+ function getNumericHeaderValue(header, key) {
12580
+ const item = header.findById(key);
12581
+ if (!item) {
12582
+ return null;
12583
+ }
12584
+ const value = Number(item.value);
12585
+ return Number.isFinite(value) ? value : null;
12586
+ }
12587
+
12588
+
12390
12589
  /***/ },
12391
12590
 
12392
12591
  /***/ 229
@@ -12591,30 +12790,47 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12591
12790
  _allSky = true;
12592
12791
  samplerIdx = 0;
12593
12792
  colorMapIdx = 0;
12594
- colorMap = ColorMaps_js_1.default['native'];
12793
+ colorMap = ColorMaps_js_1.default["native"];
12595
12794
  _healpixGrid;
12596
12795
  // exposed read-only helpers
12597
- get maxOrder() { return this._maxorder; }
12598
- get minOrder() { return this._minorder; }
12599
- get baseURL() { return this._baseurl; }
12600
- get format() { return this._format; }
12601
- get propertiesRawText() { return this._descriptor.propertiesRawText; }
12602
- get properties() { return this._descriptor.properties; }
12796
+ get maxOrder() {
12797
+ return this._maxorder;
12798
+ }
12799
+ get minOrder() {
12800
+ return this._minorder;
12801
+ }
12802
+ get baseURL() {
12803
+ return this._baseurl;
12804
+ }
12805
+ get format() {
12806
+ return this._format;
12807
+ }
12808
+ get propertiesRawText() {
12809
+ return this._descriptor.propertiesRawText;
12810
+ }
12811
+ get properties() {
12812
+ return this._descriptor.properties;
12813
+ }
12603
12814
  constructor(radius, position, xrad, yrad, descriptor, webgl, healpixGrid) {
12604
12815
  super(radius, position, xrad, yrad, descriptor.surveyName, webgl, descriptor.isGalactic);
12605
12816
  this._descriptor = descriptor;
12606
12817
  this.initGL(webgl);
12607
12818
  this._healpixGrid = healpixGrid;
12608
- this._healpixGrid.visibleTilesManager.tileBuffer.addHiPS(this);
12609
- // DEBUG logs kept from JS (optional)
12610
- // eslint-disable-next-line no-console
12611
- console.log('HiPS frame ' + descriptor.hipsFrame);
12612
- // eslint-disable-next-line no-console
12613
- console.log('HiPS minOrder ' + descriptor.minOrder);
12614
- this._format = descriptor.imgFormats[0];
12819
+ this._format = this.selectDefaultFormat(descriptor.imgFormats);
12615
12820
  this._baseurl = descriptor.url;
12616
12821
  this._maxorder = descriptor.maxOrder;
12617
12822
  this._minorder = descriptor.minOrder;
12823
+ if (this.isGalacticHips) {
12824
+ this._healpixGrid.visibleTilesManager.tileBuffer.addGalHiPS(this);
12825
+ }
12826
+ else {
12827
+ this._healpixGrid.visibleTilesManager.tileBuffer.addHiPS(this);
12828
+ }
12829
+ // DEBUG logs kept from JS (optional)
12830
+ // eslint-disable-next-line no-console
12831
+ console.log("HiPS frame " + descriptor.hipsFrame);
12832
+ // eslint-disable-next-line no-console
12833
+ console.log("HiPS minOrder " + descriptor.minOrder);
12618
12834
  this.initShaders();
12619
12835
  // pick initial order from a starting FoV
12620
12836
  const fov = 180;
@@ -12624,39 +12840,52 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12624
12840
  this._allSkyTile = null;
12625
12841
  // auto-detect all-sky: original code forces true
12626
12842
  this._allSky = true;
12843
+ this.initBaseTiles();
12844
+ }
12845
+ initBaseTiles() {
12846
+ this._ancestorTiles = [];
12847
+ this._allSkyTile = null;
12627
12848
  if (this._allSky) {
12628
12849
  this._allSkyTile = new AllSky_js_1.default(this, this._webgl, this._healpixGrid.visibleTilesManager.tileBuffer, super.hipsShaderProgram);
12850
+ return;
12629
12851
  }
12630
- else {
12631
- for (let t = 0; t < 12; t++) {
12632
- this._ancestorTiles.push(new AncestorTile_js_1.default(t, 0, this, this._healpixGrid.visibleTilesManager.tileBuffer, super.hipsShaderProgram, this._webgl));
12633
- }
12852
+ for (let t = 0; t < 12; t++) {
12853
+ this._ancestorTiles.push(new AncestorTile_js_1.default(t, 0, this, this._healpixGrid.visibleTilesManager.tileBuffer, super.hipsShaderProgram, this._webgl));
12634
12854
  }
12635
12855
  }
12636
12856
  getProperty(key) {
12637
12857
  return this._descriptor.getProperty(key);
12638
12858
  }
12639
12859
  changeFormat(format) {
12640
- this._format = format;
12641
- // original code referenced _tileBuffer; if you have one, wire it back.
12642
- // Keeping calls no-op to avoid breaking at runtime if _tileBuffer is undefined.
12643
- // (newVisibleTilesManager + TileBuffer drive the actual tile lifecycle)
12644
- // @ts-ignore
12645
- if (this._tileBuffer?.clearAll)
12646
- this._tileBuffer.clearAll();
12647
- // @ts-ignore
12648
- if (this._tileBuffer)
12649
- this._tileBuffer._format = this._format;
12650
- const pixelByOrder = this.isGalacticHips
12651
- ? this._healpixGrid.visibleTilesManager.galVisibleTilesByOrder
12652
- : this._healpixGrid.visibleTilesManager.visibleTilesByOrder;
12653
- // const pixelByOrder =
12654
- // this.isGalacticHips
12655
- // ? visibleTilesManager.galVisibleTilesByOrder
12656
- // : visibleTilesManager.visibleTilesByOrder
12657
- // @ts-ignore
12658
- if (this._tileBuffer?.updateTiles)
12659
- this._tileBuffer.updateTiles(pixelByOrder.pixels, pixelByOrder.order);
12860
+ const normalizedFormat = format.toLowerCase();
12861
+ if (!this._descriptor.imgFormats.includes(normalizedFormat)) {
12862
+ throw new Error(`HiPS format "${format}" is not supported. ` +
12863
+ `Available formats: ${this._descriptor.imgFormats.join(", ")}`);
12864
+ }
12865
+ if (normalizedFormat === this._format.toLowerCase()) {
12866
+ return;
12867
+ }
12868
+ const tileBuffer = this._healpixGrid.visibleTilesManager.tileBuffer;
12869
+ /*
12870
+ * Remove Tile instances created using the previous format.
12871
+ *
12872
+ * TileBuffer invalidates by HiPS identity/base URL rather than by the
12873
+ * current format, so both active and cached resources are discarded.
12874
+ */
12875
+ tileBuffer.invalidateHiPS(this);
12876
+ /*
12877
+ * Change format before recreating AllSky/AncestorTile because their
12878
+ * constructors read hips.format.
12879
+ */
12880
+ this._format = normalizedFormat;
12881
+ /*
12882
+ * AllSky and AncestorTile also keep the format they were constructed
12883
+ * with, so they must be recreated.
12884
+ */
12885
+ this.initBaseTiles();
12886
+ }
12887
+ get availableFormats() {
12888
+ return this._descriptor.imgFormats;
12660
12889
  }
12661
12890
  /**
12662
12891
  * Shader colormap switcher
@@ -12669,60 +12898,60 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12669
12898
  * 6 -> cubehelix
12670
12899
  */
12671
12900
  changeColorMap(colorMap) {
12672
- console.log('HiPS.changeColorMap -> shaderProgram', super.hipsShaderProgram.shaderProgram);
12901
+ console.log("HiPS.changeColorMap -> shaderProgram", super.hipsShaderProgram.shaderProgram);
12673
12902
  this.colorMap = colorMap;
12674
12903
  switch (colorMap.name) {
12675
- case 'grayscale':
12904
+ case "grayscale":
12676
12905
  this.colorMapIdx = 1;
12677
12906
  // hipsShaderProgram.setGrayscaleShader()
12678
- this.colorMap = ColorMaps_js_1.default['grayscale'];
12907
+ this.colorMap = ColorMaps_js_1.default["grayscale"];
12679
12908
  super.hipsShaderProgram.setGrayscaleShader();
12680
12909
  break;
12681
- case 'planck':
12910
+ case "planck":
12682
12911
  this.colorMapIdx = 2;
12683
- this.colorMap = ColorMaps_js_1.default['planck'];
12912
+ this.colorMap = ColorMaps_js_1.default["planck"];
12684
12913
  // hipsShaderProgram.setColorMapShader()
12685
12914
  super.hipsShaderProgram.setColorMapShader();
12686
12915
  break;
12687
- case 'cmb':
12916
+ case "cmb":
12688
12917
  this.colorMapIdx = 3;
12689
- this.colorMap = ColorMaps_js_1.default['cmb'];
12918
+ this.colorMap = ColorMaps_js_1.default["cmb"];
12690
12919
  // hipsShaderProgram.setColorMapShader()
12691
12920
  super.hipsShaderProgram.setColorMapShader();
12692
12921
  break;
12693
- case 'rainbow':
12922
+ case "rainbow":
12694
12923
  this.colorMapIdx = 4;
12695
- this.colorMap = ColorMaps_js_1.default['rainbow'];
12924
+ this.colorMap = ColorMaps_js_1.default["rainbow"];
12696
12925
  // hipsShaderProgram.setColorMapShader()
12697
12926
  super.hipsShaderProgram.setColorMapShader();
12698
12927
  break;
12699
- case 'eosb':
12928
+ case "eosb":
12700
12929
  this.colorMapIdx = 5;
12701
- this.colorMap = ColorMaps_js_1.default['eosb'];
12930
+ this.colorMap = ColorMaps_js_1.default["eosb"];
12702
12931
  super.hipsShaderProgram.setColorMapShader();
12703
12932
  // hipsShaderProgram.setColorMapShader()
12704
12933
  break;
12705
- case 'cubehelix':
12934
+ case "cubehelix":
12706
12935
  this.colorMapIdx = 6;
12707
- this.colorMap = ColorMaps_js_1.default['cubehelix'];
12936
+ this.colorMap = ColorMaps_js_1.default["cubehelix"];
12708
12937
  super.hipsShaderProgram.setColorMapShader();
12709
12938
  // hipsShaderProgram.setColorMapShader()
12710
12939
  break;
12711
- case 'hot':
12940
+ case "hot":
12712
12941
  this.colorMapIdx = 7;
12713
- this.colorMap = ColorMaps_js_1.default['hot'];
12942
+ this.colorMap = ColorMaps_js_1.default["hot"];
12714
12943
  super.hipsShaderProgram.setColorMapShader();
12715
12944
  // hipsShaderProgram.setColorMapShader()
12716
12945
  break;
12717
- case 'gray':
12946
+ case "gray":
12718
12947
  this.colorMapIdx = 8;
12719
- this.colorMap = ColorMaps_js_1.default['gray'];
12948
+ this.colorMap = ColorMaps_js_1.default["gray"];
12720
12949
  super.hipsShaderProgram.setColorMapShader();
12721
12950
  // hipsShaderProgram.setColorMapShader()
12722
12951
  break;
12723
- case 'native':
12952
+ case "native":
12724
12953
  this.colorMapIdx = 0;
12725
- this.colorMap = ColorMaps_js_1.default['native'];
12954
+ this.colorMap = ColorMaps_js_1.default["native"];
12726
12955
  super.hipsShaderProgram.setNativeShader();
12727
12956
  break;
12728
12957
  default:
@@ -12737,6 +12966,30 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12737
12966
  // this.shaderProgram = super.hipsShaderProgram.shaderProgram
12738
12967
  // this.shaderProgram = hipsShaderProgram.shaderProgram
12739
12968
  }
12969
+ // private selectDefaultFormat(formats: string[]): string {
12970
+ // if (formats.includes("fits")) return "fits";
12971
+ // if (formats.includes("png")) return "png";
12972
+ // if (formats.includes("jpg")) return "jpg";
12973
+ // if (formats.length > 0) {
12974
+ // return formats[0];
12975
+ // }
12976
+ // throw new Error("HiPS descriptor does not define a tile format");
12977
+ // }
12978
+ selectDefaultFormat(formats) {
12979
+ if (formats.includes("png"))
12980
+ return "png";
12981
+ if (formats.includes("jpg"))
12982
+ return "jpg";
12983
+ if (formats.includes("fits"))
12984
+ return "fits";
12985
+ if (formats.length > 0) {
12986
+ return formats[0];
12987
+ }
12988
+ throw new Error("HiPS descriptor does not define a tile format");
12989
+ }
12990
+ get dataRange() {
12991
+ return this._descriptor.dataRange;
12992
+ }
12740
12993
  getCurrentHealpixOrder() {
12741
12994
  return this._visibleorder;
12742
12995
  }
@@ -12746,7 +12999,7 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12746
12999
  ? this._healpixGrid.visibleTilesManager.galVisibleTilesByOrder
12747
13000
  : this._healpixGrid.visibleTilesManager.visibleTilesByOrder;
12748
13001
  return {
12749
- activeBaseLayer: 'hips',
13002
+ activeBaseLayer: "hips",
12750
13003
  hipsName: this._descriptor.surveyName,
12751
13004
  hipsUrl: this._baseurl,
12752
13005
  isGalactic: this.isGalacticHips,
@@ -12778,16 +13031,10 @@ class HiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
12778
13031
  super.hipsShaderProgram.setRuntimeColorMap(this.colorMap);
12779
13032
  if (this._allSky && this._allSkyTile) {
12780
13033
  if (this.isGalacticHips) {
12781
- this._allSkyTile.draw(this._healpixGrid.visibleTilesManager.galVisibleTilesByOrder.order, this._healpixGrid.visibleTilesManager.galAncestorsMap,
12782
- // visibleTilesManager.galVisibleTilesByOrder.order,
12783
- // visibleTilesManager.galAncestorsMap,
12784
- pMatrix, vMatrix, mMatrix, this.colorMapIdx);
13034
+ this._allSkyTile.draw(this._healpixGrid.visibleTilesManager.galVisibleTilesByOrder.order, this._healpixGrid.visibleTilesManager.galAncestorsMap, pMatrix, vMatrix, mMatrix, this.colorMapIdx);
12785
13035
  }
12786
13036
  else {
12787
- this._allSkyTile.draw(this._healpixGrid.visibleTilesManager.visibleTilesByOrder.order, this._healpixGrid.visibleTilesManager.ancestorsMap,
12788
- // visibleTilesManager.visibleTilesByOrder.order,
12789
- // visibleTilesManager.ancestorsMap,
12790
- pMatrix, vMatrix, mMatrix, this.colorMapIdx);
13037
+ this._allSkyTile.draw(this._healpixGrid.visibleTilesManager.visibleTilesByOrder.order, this._healpixGrid.visibleTilesManager.ancestorsMap, pMatrix, vMatrix, mMatrix, this.colorMapIdx);
12791
13038
  }
12792
13039
  return;
12793
13040
  }
@@ -12980,6 +13227,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
12980
13227
  // Tile.ts
12981
13228
  const Global_js_1 = __importDefault(__webpack_require__(4382));
12982
13229
  const FoVHelper_js_1 = __webpack_require__(229);
13230
+ const FitsTileLoader_js_1 = __webpack_require__(1399);
12983
13231
  // ------------------------------------------------------------------------
12984
13232
  class Tile {
12985
13233
  _hips;
@@ -12994,8 +13242,9 @@ class Tile {
12994
13242
  _image;
12995
13243
  _textureLoaded = false;
12996
13244
  _texture;
12997
- _texurl = '';
13245
+ _texurl = "";
12998
13246
  _hipsShaderIndex = 0;
13247
+ _fitsTile;
12999
13248
  _cacheTime0;
13000
13249
  _inView = true;
13001
13250
  _amIStillInFoV_requsetID;
@@ -13052,50 +13301,66 @@ class Tile {
13052
13301
  console.warn(`[Tile] Skipping tile request above max order: requested order ${this._order}, max order ${this._maxorder}, url ${this._baseurl}`);
13053
13302
  return;
13054
13303
  }
13055
- this._image = new Image();
13056
13304
  const dirnumber = Math.floor(this._tileno / 10000) * 10000;
13057
13305
  this._texurl = `${this._baseurl}/Norder${this._order}/Dir${dirnumber}/Npix${this._tileno}.${this._format}`;
13306
+ if (this._format === "fits") {
13307
+ void this.loadFits();
13308
+ return;
13309
+ }
13310
+ this.loadImage();
13311
+ }
13312
+ loadImage() {
13313
+ this._image = new Image();
13058
13314
  this._image.onload = () => this.imageLoaded();
13059
13315
  this._image.onerror = () => {
13060
- // console.error('File not found?', this._texurl)
13061
13316
  this._ready = false;
13062
13317
  this._abort = true;
13063
13318
  this.destroyIntervals();
13064
13319
  };
13065
- this._image.crossOrigin = 'anonymous';
13320
+ this._image.crossOrigin = "anonymous";
13066
13321
  this._image.src = this._texurl;
13067
13322
  }
13323
+ async loadFits() {
13324
+ try {
13325
+ this._fitsTile = await (0, FitsTileLoader_js_1.loadFitsTile)(this._texurl);
13326
+ this._ready = true;
13327
+ }
13328
+ catch (error) {
13329
+ console.error(`[Tile] Unable to load FITS tile ${this._texurl}`, error);
13330
+ this._ready = false;
13331
+ this._abort = true;
13332
+ this.destroyIntervals();
13333
+ }
13334
+ }
13068
13335
  imageLoaded() {
13069
13336
  // this.textureLoaded()
13070
13337
  // this.initModelBuffer()
13071
13338
  // this._textureLoaded = true
13072
13339
  this._ready = true;
13073
13340
  }
13074
- // private textureLoaded(): void {
13075
13341
  textureLoaded(hipsShaderProgram) {
13076
- // this._hipsShaderProgram.enableProgram()
13077
13342
  hipsShaderProgram.enableProgram();
13078
13343
  const gl = this._webgl;
13079
13344
  this._texture = gl.createTexture();
13080
13345
  gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
13081
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
13346
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this._format !== "fits");
13082
13347
  gl.bindTexture(gl.TEXTURE_2D, this._texture);
13083
- if (!gl.isTexture(this._texture)) {
13084
- console.log('error in texture');
13348
+ if (this._format === "fits") {
13349
+ const fits = this._fitsTile;
13350
+ if (!fits) {
13351
+ throw new Error(`FITS tile data not loaded: ${this._texurl}`);
13352
+ }
13353
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, fits.width, fits.height, 0, gl.RED, gl.FLOAT, fits.pixels);
13354
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
13355
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
13356
+ }
13357
+ else {
13358
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
13359
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
13360
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
13085
13361
  }
13086
- gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
13087
- gl.bindTexture(gl.TEXTURE_2D, this._texture);
13088
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
13089
13362
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
13090
13363
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
13091
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
13092
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
13093
- // FIX: use the sampler location we fetched in enableShaders()
13094
- // gl.uniform1i((this._hipsShaderProgram.locations as ShaderLocations).sampler, this._hipsShaderIndex)
13095
- // gl.uniform1i((hipsShaderProgram.locations as ShaderLocations).sampler, this._hipsShaderIndex)
13096
- if (!gl.isTexture(this._texture)) {
13097
- console.warn('Texture creation failed');
13098
- }
13099
13364
  this.initModelBuffer();
13100
13365
  this._textureLoaded = true;
13101
13366
  }
@@ -13162,26 +13427,32 @@ class Tile {
13162
13427
  this.vertexPosition[qidx][20 * p] = facesVec3Array[0].x;
13163
13428
  this.vertexPosition[qidx][20 * p + 1] = facesVec3Array[0].y;
13164
13429
  this.vertexPosition[qidx][20 * p + 2] = facesVec3Array[0].z;
13165
- this.vertexPosition[qidx][20 * p + 3] = step + step * uindex + s_pixel_size;
13166
- this.vertexPosition[qidx][20 * p + 4] = 1 - (step + step * vindex) - t_pixel_size;
13430
+ this.vertexPosition[qidx][20 * p + 3] =
13431
+ step + step * uindex + s_pixel_size;
13432
+ this.vertexPosition[qidx][20 * p + 4] =
13433
+ 1 - (step + step * vindex) - t_pixel_size;
13167
13434
  // v1
13168
13435
  this.vertexPosition[qidx][20 * p + 5] = facesVec3Array[1].x;
13169
13436
  this.vertexPosition[qidx][20 * p + 6] = facesVec3Array[1].y;
13170
13437
  this.vertexPosition[qidx][20 * p + 7] = facesVec3Array[1].z;
13171
- this.vertexPosition[qidx][20 * p + 8] = step + step * uindex + s_pixel_size;
13172
- this.vertexPosition[qidx][20 * p + 9] = 1 - step * vindex + t_pixel_size;
13438
+ this.vertexPosition[qidx][20 * p + 8] =
13439
+ step + step * uindex + s_pixel_size;
13440
+ this.vertexPosition[qidx][20 * p + 9] =
13441
+ 1 - step * vindex + t_pixel_size;
13173
13442
  // v2
13174
13443
  this.vertexPosition[qidx][20 * p + 10] = facesVec3Array[2].x;
13175
13444
  this.vertexPosition[qidx][20 * p + 11] = facesVec3Array[2].y;
13176
13445
  this.vertexPosition[qidx][20 * p + 12] = facesVec3Array[2].z;
13177
13446
  this.vertexPosition[qidx][20 * p + 13] = step * uindex - s_pixel_size;
13178
- this.vertexPosition[qidx][20 * p + 14] = 1 - step * vindex + t_pixel_size;
13447
+ this.vertexPosition[qidx][20 * p + 14] =
13448
+ 1 - step * vindex + t_pixel_size;
13179
13449
  // v3
13180
13450
  this.vertexPosition[qidx][20 * p + 15] = facesVec3Array[3].x;
13181
13451
  this.vertexPosition[qidx][20 * p + 16] = facesVec3Array[3].y;
13182
13452
  this.vertexPosition[qidx][20 * p + 17] = facesVec3Array[3].z;
13183
13453
  this.vertexPosition[qidx][20 * p + 18] = step * uindex - s_pixel_size;
13184
- this.vertexPosition[qidx][20 * p + 19] = 1 - (step + step * vindex) - t_pixel_size;
13454
+ this.vertexPosition[qidx][20 * p + 19] =
13455
+ 1 - (step + step * vindex) - t_pixel_size;
13185
13456
  p++;
13186
13457
  }
13187
13458
  }
@@ -13189,6 +13460,32 @@ class Tile {
13189
13460
  gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBuffer[qidx]);
13190
13461
  gl.bufferData(gl.ARRAY_BUFFER, this.vertexPosition[qidx], gl.STATIC_DRAW);
13191
13462
  }
13463
+ getFitsDataRange() {
13464
+ const hipsRange = this._hips.dataRange;
13465
+ if (hipsRange.min !== undefined &&
13466
+ hipsRange.max !== undefined &&
13467
+ Number.isFinite(hipsRange.min) &&
13468
+ Number.isFinite(hipsRange.max) &&
13469
+ hipsRange.max > hipsRange.min) {
13470
+ return {
13471
+ min: hipsRange.min,
13472
+ max: hipsRange.max,
13473
+ };
13474
+ }
13475
+ const fits = this._fitsTile;
13476
+ if (fits &&
13477
+ fits.dataMin !== null &&
13478
+ fits.dataMax !== null &&
13479
+ Number.isFinite(fits.dataMin) &&
13480
+ Number.isFinite(fits.dataMax) &&
13481
+ fits.dataMax > fits.dataMin) {
13482
+ return {
13483
+ min: fits.dataMin,
13484
+ max: fits.dataMax,
13485
+ };
13486
+ }
13487
+ return null;
13488
+ }
13192
13489
  get inView() {
13193
13490
  return this._inView;
13194
13491
  }
@@ -13203,7 +13500,9 @@ class Tile {
13203
13500
  this._ready = true;
13204
13501
  if (this._isGalacticHips) {
13205
13502
  if (this._visibleTileManager.galAncestorsMap.has(this._order)) {
13206
- if (!this._visibleTileManager.galAncestorsMap.get(this._order).includes(this._tileno)) {
13503
+ if (!this._visibleTileManager.galAncestorsMap
13504
+ .get(this._order)
13505
+ .includes(this._tileno)) {
13207
13506
  this.moveToCache();
13208
13507
  }
13209
13508
  else {
@@ -13235,7 +13534,9 @@ class Tile {
13235
13534
  }
13236
13535
  else {
13237
13536
  if (this._visibleTileManager.ancestorsMap.has(this._order)) {
13238
- if (!this._visibleTileManager.ancestorsMap.get(this._order).includes(this._tileno)) {
13537
+ if (!this._visibleTileManager.ancestorsMap
13538
+ .get(this._order)
13539
+ .includes(this._tileno)) {
13239
13540
  this.moveToCache();
13240
13541
  }
13241
13542
  else {
@@ -13281,33 +13582,39 @@ class Tile {
13281
13582
  }
13282
13583
  const gl = this._webgl;
13283
13584
  hipsShaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx);
13284
- // this._hipsShaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx)
13285
- // Enable attributes (these locations are retrieved in enableShaders)
13286
- // gl.enableVertexAttribArray(this._hipsShaderProgram.locations.vertexPositionAttribute)
13287
- // gl.enableVertexAttribArray(this._hipsShaderProgram.locations.textureCoordAttribute)
13288
- gl.enableVertexAttribArray(hipsShaderProgram.locations.vertexPositionAttribute);
13289
- gl.enableVertexAttribArray(hipsShaderProgram.locations.textureCoordAttribute);
13585
+ if (this._format === "fits") {
13586
+ const range = this.getFitsDataRange();
13587
+ if (!range) {
13588
+ console.error(`[Tile] No display range available for FITS tile ${this._texurl}`);
13589
+ return;
13590
+ }
13591
+ hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, true, range.min, range.max);
13592
+ }
13593
+ else {
13594
+ hipsShaderProgram.setTextureDataMode(this._hipsShaderIndex, false);
13595
+ }
13596
+ const locations = hipsShaderProgram.locations;
13597
+ gl.enableVertexAttribArray(locations.vertexPositionAttribute);
13598
+ gl.enableVertexAttribArray(locations.textureCoordAttribute);
13290
13599
  gl.activeTexture(gl.TEXTURE0 + this._hipsShaderIndex);
13291
13600
  gl.bindTexture(gl.TEXTURE_2D, this._texture);
13292
- // gl.uniform1f(this._hipsShaderProgram.locations.textureAlpha, this.opacity)
13293
- gl.uniform1f(hipsShaderProgram.locations.textureAlpha, this.opacity);
13601
+ const factorLocation = locations.textureAlpha[this._hipsShaderIndex];
13602
+ if (factorLocation) {
13603
+ gl.uniform1f(factorLocation, this.opacity);
13604
+ }
13294
13605
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.vertexIndexBuffer);
13295
13606
  const elemno = this.vertexIndices.length;
13296
- const indexType = this.vertexIndices instanceof Uint32Array ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT;
13607
+ const indexType = this.vertexIndices instanceof Uint32Array
13608
+ ? gl.UNSIGNED_INT
13609
+ : gl.UNSIGNED_SHORT;
13297
13610
  quadrantsToDraw.forEach((qidx) => {
13298
13611
  gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBuffer[qidx]);
13299
- gl.vertexAttribPointer(
13300
- // this._hipsShaderProgram.locations.vertexPositionAttribute,
13301
- hipsShaderProgram.locations.vertexPositionAttribute, 3, gl.FLOAT, false, 5 * 4, 0);
13302
- gl.vertexAttribPointer(
13303
- // this._hipsShaderProgram.locations.textureCoordAttribute,
13304
- hipsShaderProgram.locations.textureCoordAttribute, 2, gl.FLOAT, false, 5 * 4, 3 * 4);
13612
+ gl.vertexAttribPointer(locations.vertexPositionAttribute, 3, gl.FLOAT, false, 5 * 4, 0);
13613
+ gl.vertexAttribPointer(locations.textureCoordAttribute, 2, gl.FLOAT, false, 5 * 4, 3 * 4);
13305
13614
  gl.drawElements(gl.TRIANGLES, elemno, indexType, 0);
13306
13615
  });
13307
- // gl.disableVertexAttribArray(this._hipsShaderProgram.locations.vertexPositionAttribute)
13308
- // gl.disableVertexAttribArray(this._hipsShaderProgram.locations.textureCoordAttribute)
13309
- gl.disableVertexAttribArray(hipsShaderProgram.locations.vertexPositionAttribute);
13310
- gl.disableVertexAttribArray(hipsShaderProgram.locations.textureCoordAttribute);
13616
+ gl.disableVertexAttribArray(locations.vertexPositionAttribute);
13617
+ gl.disableVertexAttribArray(locations.textureCoordAttribute);
13311
13618
  }
13312
13619
  drawChildren(visibleOrder, visibleTilesMap, pMatrix, vMatrix, mMatrix, colorMapIdx, hipsShaderProgram) {
13313
13620
  const quadrantsToDraw = new Set([0, 1, 2, 3]);
@@ -13321,13 +13628,9 @@ class Tile {
13321
13628
  const childTile = this._isGalacticHips
13322
13629
  ? this._tileBuffer.getGalTile(childTileNo, childrenOrder, this._hips)
13323
13630
  : this._tileBuffer.getTile(childTileNo, childrenOrder, this._hips);
13324
- // const childTile = this._isGalacticHips
13325
- // ? newTileBuffer.getGalTile(childTileNo, childrenOrder, this._hips)
13326
- // : newTileBuffer.getTile(childTileNo, childrenOrder, this._hips)
13327
- // childTile.draw(visibleOrder, visibleTilesMap, pMatrix, vMatrix, mMatrix, colorMapIdx)
13328
13631
  childTile.draw(visibleOrder, visibleTilesMap, pMatrix, vMatrix, mMatrix, colorMapIdx, hipsShaderProgram);
13329
- if (childTile._ready) {
13330
- quadrantsToDraw.delete(childTileNo - (this._tileno << 2));
13632
+ if (childTile.getReadyState()) {
13633
+ quadrantsToDraw.delete(c);
13331
13634
  }
13332
13635
  }
13333
13636
  }
@@ -13393,7 +13696,7 @@ class TileBuffer {
13393
13696
  /** Register an equatorial HiPS into the buffer. */
13394
13697
  addHiPS(hips) {
13395
13698
  if (this._activeHiPS.has(hips)) {
13396
- console.error('HiPS already present in TileBuffer');
13699
+ console.error("HiPS already present in TileBuffer");
13397
13700
  return;
13398
13701
  }
13399
13702
  this._activeHiPS.set(hips, new Map());
@@ -13401,7 +13704,7 @@ class TileBuffer {
13401
13704
  /** Register a galactic HiPS into the buffer. */
13402
13705
  addGalHiPS(hips) {
13403
13706
  if (this._galActiveHiPS.has(hips)) {
13404
- console.error('HiPS already present in TileBuffer');
13707
+ console.error("HiPS already present in TileBuffer");
13405
13708
  return;
13406
13709
  }
13407
13710
  this._galActiveHiPS.set(hips, new Map());
@@ -13426,7 +13729,7 @@ class TileBuffer {
13426
13729
  }
13427
13730
  /** Fetch (or create) an equatorial tile, reviving from cache if present. */
13428
13731
  getTile(tileno, order, hips) {
13429
- const tileKey = this.key(order, tileno, hips.baseURL);
13732
+ const tileKey = this.key(order, tileno, hips);
13430
13733
  if (!this._tiles.has(tileKey)) {
13431
13734
  if (this._cachedTiles.has(tileKey)) {
13432
13735
  const tile = this._cachedTiles.get(tileKey);
@@ -13444,7 +13747,7 @@ class TileBuffer {
13444
13747
  }
13445
13748
  /** Fetch (or create) a galactic tile, reviving from cache if present. */
13446
13749
  getGalTile(tileno, order, hips) {
13447
- const tileKey = this.key(order, tileno, hips.baseURL);
13750
+ const tileKey = this.key(order, tileno, hips);
13448
13751
  if (!this._galTiles.has(tileKey)) {
13449
13752
  if (this._galCachedTiles.has(tileKey)) {
13450
13753
  const tile = this._galCachedTiles.get(tileKey);
@@ -13462,7 +13765,7 @@ class TileBuffer {
13462
13765
  }
13463
13766
  /** Move a tile (equatorial or galactic) into cache. */
13464
13767
  moveTileToCache(tileno, order, hips) {
13465
- const tileKey = this.key(order, tileno, hips.baseURL);
13768
+ const tileKey = this.key(order, tileno, hips);
13466
13769
  if (this._tiles.has(tileKey)) {
13467
13770
  const tile = this._tiles.get(tileKey);
13468
13771
  tile.setCacheTime0();
@@ -13481,29 +13784,64 @@ class TileBuffer {
13481
13784
  const now = Date.now();
13482
13785
  for (const [tileKey, tile] of this._cachedTiles) {
13483
13786
  const t0 = tile.cacheTime0;
13484
- if (!tile.inView && t0 !== undefined && now - t0 > this._cacheAliveMilliSeconds) {
13787
+ if (!tile.inView &&
13788
+ t0 !== undefined &&
13789
+ now - t0 > this._cacheAliveMilliSeconds) {
13485
13790
  tile.destroyIntervals();
13486
13791
  this._cachedTiles.delete(tileKey);
13487
13792
  }
13488
13793
  }
13489
13794
  for (const [tileKey, tile] of this._galCachedTiles) {
13490
13795
  const t0 = tile.cacheTime0;
13491
- if (!tile.inView && t0 !== undefined && now - t0 > this._cacheAliveMilliSeconds) {
13796
+ if (!tile.inView &&
13797
+ t0 !== undefined &&
13798
+ now - t0 > this._cacheAliveMilliSeconds) {
13492
13799
  tile.destroyIntervals();
13493
13800
  this._galCachedTiles.delete(tileKey);
13494
13801
  }
13495
13802
  }
13496
13803
  }
13497
13804
  /** Compose a stable key for maps. */
13498
- key(order, tileno, baseURL) {
13499
- return `${order}#${tileno}#${baseURL}`;
13805
+ key(order, tileno, hips) {
13806
+ return `${order}#${tileno}#${hips.baseURL}#${hips.format}`;
13807
+ }
13808
+ removeHiPS(hips) {
13809
+ this.invalidateHiPS(hips);
13810
+ this._activeHiPS.delete(hips);
13811
+ this._galActiveHiPS.delete(hips);
13812
+ }
13813
+ /**
13814
+ * Remove all active and cached tiles belonging to a specific HiPS.
13815
+ *
13816
+ * Tile keys contain the HiPS base URL and format. We intentionally
13817
+ * ignore the format here so that a format change removes resources
13818
+ * created with the previous format as well.
13819
+ */
13820
+ invalidateHiPS(hips) {
13821
+ const belongsToHiPS = (tileKey) => tileKey.includes(`#${hips.baseURL}#`);
13822
+ const clearTiles = (tiles) => {
13823
+ for (const [tileKey, tile] of tiles) {
13824
+ if (!belongsToHiPS(tileKey)) {
13825
+ continue;
13826
+ }
13827
+ tile.destroyIntervals();
13828
+ tiles.delete(tileKey);
13829
+ }
13830
+ };
13831
+ clearTiles(this._tiles);
13832
+ clearTiles(this._cachedTiles);
13833
+ clearTiles(this._galTiles);
13834
+ clearTiles(this._galCachedTiles);
13500
13835
  }
13501
13836
  /** Optional: call to stop internal timers if you dispose this buffer. */
13502
13837
  dispose() {
13503
13838
  window.clearInterval(this._cleanerId);
13504
13839
  }
13505
13840
  get size() {
13506
- return this._tiles.size + this._cachedTiles.size + this._galTiles.size + this._galCachedTiles.size;
13841
+ return (this._tiles.size +
13842
+ this._cachedTiles.size +
13843
+ this._galTiles.size +
13844
+ this._galCachedTiles.size);
13507
13845
  }
13508
13846
  get activeTileCount() {
13509
13847
  return this._tiles.size + this._galTiles.size;
@@ -13581,11 +13919,8 @@ exports.VisibleTilesManager = void 0;
13581
13919
  const Global_js_1 = __importDefault(__webpack_require__(4382));
13582
13920
  const healpix_1 = __webpack_require__(4851);
13583
13921
  const RayPickingUtils_js_1 = __importDefault(__webpack_require__(4639));
13584
- // import { newTileBuffer } from './TileBuffer.js';
13585
13922
  const TileBuffer_js_1 = __webpack_require__(4006);
13586
13923
  const gl_matrix_1 = __webpack_require__(3890);
13587
- // import healpixGridSingleton from '../grid/HealpixGridSingleton.js';
13588
- // import {HealpixGridSingleton} from '../grid/HealpixGridSingleton.js';
13589
13924
  const Config_js_1 = __webpack_require__(2919);
13590
13925
  class VisibleTilesManager {
13591
13926
  _visibleTilesByOrder;
@@ -13625,18 +13960,13 @@ class VisibleTilesManager {
13625
13960
  init(insideSphere) {
13626
13961
  this.initialised = true;
13627
13962
  this.insideSphere = insideSphere;
13628
- // this.computeVisiblePixels();
13629
- // setInterval(() => this.computeVisiblePixels(), 500);
13630
13963
  }
13631
13964
  getVisibleOrder() {
13632
- // return healpixGridSingleton.visibleorder;
13633
13965
  return this._healpixGrid.visibleorder;
13634
13966
  }
13635
- // computeVisiblePixels(): void {
13636
13967
  computeVisiblePixels(order, webgl, camera, pMatrix) {
13637
13968
  if (!this.initialised)
13638
13969
  return;
13639
- // let order = healpixGridSingleton.visibleorder;
13640
13970
  if (Global_js_1.default.insideSphere && order < 3) {
13641
13971
  order = 3;
13642
13972
  }
@@ -13656,8 +13986,6 @@ class VisibleTilesManager {
13656
13986
  }
13657
13987
  else {
13658
13988
  const geomhealpix = Global_js_1.default.getHealpix(order);
13659
- // const maxX = (global.gl as GL).canvas.width;
13660
- // const maxY = (global.gl as GL).canvas.height;
13661
13989
  const maxX = webgl.canvas.width;
13662
13990
  const maxY = webgl.canvas.height;
13663
13991
  // Sample a grid of screen points, project to the sphere, then to galactic
@@ -13677,13 +14005,11 @@ class VisibleTilesManager {
13677
14005
  if (!pixels.includes(currPixNo)) {
13678
14006
  pixels.push(currPixNo);
13679
14007
  this._ancestorsMap.get(order).push(currPixNo);
13680
- // newTileBuffer.addTile(order, currPixNo);
13681
14008
  this._tileBuffer.addTile(order, currPixNo);
13682
14009
  }
13683
14010
  if (!galTiles.includes(galTileNo)) {
13684
14011
  galTiles.push(galTileNo);
13685
14012
  this._galAncestorsMap.get(order).push(galTileNo);
13686
- // newTileBuffer.addGalTile(order, galTileNo);
13687
14013
  this._tileBuffer.addGalTile(order, galTileNo);
13688
14014
  }
13689
14015
  }
@@ -13701,7 +14027,6 @@ class VisibleTilesManager {
13701
14027
  const parent = pixels[p] >> (2 * o);
13702
14028
  if (!list.includes(parent)) {
13703
14029
  list.push(parent);
13704
- // newTileBuffer.addTile(tgtOrder, parent);
13705
14030
  this._tileBuffer.addTile(tgtOrder, parent);
13706
14031
  }
13707
14032
  }
@@ -13714,7 +14039,6 @@ class VisibleTilesManager {
13714
14039
  const parent = galTiles[p] >> (2 * o);
13715
14040
  if (!list.includes(parent)) {
13716
14041
  list.push(parent);
13717
- // newTileBuffer.addGalTile(tgtOrder, parent);
13718
14042
  this._tileBuffer.addGalTile(tgtOrder, parent);
13719
14043
  }
13720
14044
  }
@@ -16078,7 +16402,7 @@ class HiPSShaderProgram {
16078
16402
  _UBO_colorMapVariableInfo = {
16079
16403
  r_palette: { index: 0, offset: 0 },
16080
16404
  g_palette: { index: 0, offset: 0 },
16081
- b_palette: { index: 0, offset: 0 }
16405
+ b_palette: { index: 0, offset: 0 },
16082
16406
  };
16083
16407
  gl_uniforms;
16084
16408
  gl_attributes;
@@ -16087,54 +16411,60 @@ class HiPSShaderProgram {
16087
16411
  constructor(webgl) {
16088
16412
  this._webgl = webgl;
16089
16413
  this.gl_uniforms = {
16090
- sampler: 'uSampler0',
16091
- factor: 'uFactor0',
16092
- m_perspective: 'uPMatrix',
16093
- m_model: 'uMMatrix',
16094
- m_view: 'uVMatrix',
16095
- colormapIdx: 'cmapIdx',
16096
- colormap_red: 'r',
16097
- colormap_green: 'g',
16098
- colormap_blue: 'b'
16414
+ sampler: "uSampler0",
16415
+ factor: "uFactor0",
16416
+ m_perspective: "uPMatrix",
16417
+ m_model: "uMMatrix",
16418
+ m_view: "uVMatrix",
16419
+ colormapIdx: "cmapIdx",
16420
+ colormap_red: "r",
16421
+ colormap_green: "g",
16422
+ colormap_blue: "b",
16423
+ textureMode: "uTextureMode",
16424
+ dataMin: "uDataMin",
16425
+ dataMax: "uDataMax",
16099
16426
  };
16100
16427
  this.gl_attributes = {
16101
- vertex_pos: 'aVertexPosition',
16102
- text_coords: 'aTextureCoord'
16428
+ vertex_pos: "aVertexPosition",
16429
+ text_coords: "aTextureCoord",
16103
16430
  };
16104
16431
  this.locations = {
16105
16432
  pMatrix: null,
16106
16433
  mMatrix: null,
16107
16434
  vMatrix: null,
16108
- sampler: null,
16109
- textureAlpha: null,
16435
+ samplers: new Array(8).fill(null),
16436
+ textureAlpha: new Array(8).fill(null),
16437
+ textureMode: new Array(8).fill(null),
16438
+ dataMin: new Array(8).fill(null),
16439
+ dataMax: new Array(8).fill(null),
16110
16440
  clorMapIdx: null,
16111
16441
  vertexPositionAttribute: -1,
16112
- textureCoordAttribute: -1
16442
+ textureCoordAttribute: -1,
16113
16443
  };
16114
16444
  }
16115
16445
  get shaderProgram() {
16116
16446
  const gl = this._webgl;
16117
16447
  if (!this._shaderProgram) {
16118
- // const gl = global.gl as GL
16119
- this._shaderProgram = gl.createProgram();
16120
- this.initShaders();
16448
+ const program = gl.createProgram();
16449
+ this._shaderProgram = program;
16450
+ this.initShaders(program);
16121
16451
  }
16122
- ;
16123
16452
  gl.useProgram(this._shaderProgram);
16124
16453
  return this._shaderProgram;
16125
16454
  }
16126
16455
  setRuntimeColorMap(colorMap) {
16127
16456
  this._runtimeColorMap = colorMap;
16128
16457
  }
16129
- initShaders() {
16130
- // const gl = global.gl as GL
16458
+ initShaders(program) {
16459
+ // const gl = global.gl
16131
16460
  const gl = this._webgl;
16132
16461
  const fragmentShaderStr = ShaderManager_js_1.default.hipsNativeFS();
16133
16462
  this._fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
16134
16463
  gl.shaderSource(this._fragmentShader, fragmentShaderStr);
16135
16464
  gl.compileShader(this._fragmentShader);
16136
16465
  if (!gl.getShaderParameter(this._fragmentShader, gl.COMPILE_STATUS)) {
16137
- alert(gl.getShaderInfoLog(this._fragmentShader) || 'Fragment shader compile error');
16466
+ alert(gl.getShaderInfoLog(this._fragmentShader) ||
16467
+ "Fragment shader compile error");
16138
16468
  return;
16139
16469
  }
16140
16470
  const vertexShaderStr = ShaderManager_js_1.default.hipsVS();
@@ -16142,43 +16472,44 @@ class HiPSShaderProgram {
16142
16472
  gl.shaderSource(this._vertexShader, vertexShaderStr);
16143
16473
  gl.compileShader(this._vertexShader);
16144
16474
  if (!gl.getShaderParameter(this._vertexShader, gl.COMPILE_STATUS)) {
16145
- alert(gl.getShaderInfoLog(this._vertexShader) || 'Vertex shader compile error');
16475
+ alert(gl.getShaderInfoLog(this._vertexShader) ||
16476
+ "Vertex shader compile error");
16146
16477
  return;
16147
16478
  }
16148
- gl.attachShader(this._shaderProgram, this._vertexShader);
16149
- gl.attachShader(this._shaderProgram, this._fragmentShader);
16150
- gl.linkProgram(this._shaderProgram);
16151
- if (!gl.getProgramParameter(this._shaderProgram, gl.LINK_STATUS)) {
16152
- alert('Could not initialise shaders');
16479
+ gl.attachShader(program, this._vertexShader);
16480
+ gl.attachShader(program, this._fragmentShader);
16481
+ gl.linkProgram(program);
16482
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
16483
+ alert("Could not initialise shaders");
16153
16484
  }
16154
16485
  }
16155
16486
  enableProgram() {
16156
- // (global.gl as GL).useProgram(this._shaderProgram as WebGLProgram)
16487
+ // (global.gl).useProgram(this._shaderProgram)
16157
16488
  this._webgl.useProgram(this.shaderProgram);
16158
16489
  }
16159
16490
  setGrayscaleShader() {
16160
- // const gl = global.gl as GL
16491
+ // const gl = global.gl
16161
16492
  const gl = this._webgl;
16162
16493
  gl.detachShader(this.shaderProgram, this._fragmentShader);
16163
16494
  const fragmentShaderStr = ShaderManager_js_1.default.hipsGrayscaleFS();
16164
16495
  this.changeFSShader(fragmentShaderStr);
16165
16496
  }
16166
16497
  setNativeShader() {
16167
- // const gl = global.gl as GL
16498
+ // const gl = global.gl
16168
16499
  const gl = this._webgl;
16169
16500
  gl.detachShader(this.shaderProgram, this._fragmentShader);
16170
16501
  const fragmentShaderStr = ShaderManager_js_1.default.hipsNativeFS();
16171
16502
  this.changeFSShader(fragmentShaderStr);
16172
16503
  }
16173
16504
  setColorMapShader() {
16174
- // const gl = global.gl as GL
16505
+ // const gl = global.gl
16175
16506
  const gl = this._webgl;
16176
16507
  // Swap fragment shader
16177
16508
  gl.detachShader(this.shaderProgram, this._fragmentShader);
16178
16509
  const fragmentShaderStr = ShaderManager_js_1.default.hipsColorMapFS();
16179
16510
  this.changeFSShader(fragmentShaderStr);
16180
16511
  // UBO discovery for the "colormap" block
16181
- const blockIndex = gl.getUniformBlockIndex(this.shaderProgram, 'colormap');
16512
+ const blockIndex = gl.getUniformBlockIndex(this.shaderProgram, "colormap");
16182
16513
  // INVALID_INDEX == 0xFFFFFFFF in WebGL2
16183
16514
  if (blockIndex === gl.INVALID_INDEX) {
16184
16515
  console.warn('HiPSShaderProgram: uniform block "colormap" not found in hipsColorMapFS()');
@@ -16188,11 +16519,11 @@ class HiPSShaderProgram {
16188
16519
  }
16189
16520
  this._colorMapBlockIndex = blockIndex;
16190
16521
  // const blockSize = gl.getActiveUniformBlockParameter(
16191
- // this.shaderProgram as WebGLProgram,
16522
+ // this.shaderProgram,
16192
16523
  // blockIndex,
16193
16524
  // gl.UNIFORM_BLOCK_DATA_SIZE
16194
16525
  // ) as number
16195
- const uboVariableNames = ['r_palette', 'g_palette', 'b_palette'];
16526
+ const uboVariableNames = ["r_palette", "g_palette", "b_palette"];
16196
16527
  const uboVariableIndices = gl.getUniformIndices(this.shaderProgram, uboVariableNames);
16197
16528
  const uboVariableOffsets = gl.getActiveUniforms(this.shaderProgram, uboVariableIndices, gl.UNIFORM_OFFSET);
16198
16529
  // Create buffer only once
@@ -16209,49 +16540,80 @@ class HiPSShaderProgram {
16209
16540
  uboVariableNames.forEach((name, index) => {
16210
16541
  this._UBO_colorMapVariableInfo[name] = {
16211
16542
  index: uboVariableIndices[index],
16212
- offset: uboVariableOffsets[index]
16543
+ offset: uboVariableOffsets[index],
16213
16544
  };
16214
16545
  });
16215
16546
  }
16216
16547
  changeFSShader(fragmentShaderStr) {
16217
- // const gl = global.gl as GL
16548
+ // const gl = global.gl
16218
16549
  const gl = this._webgl;
16219
16550
  this._fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
16220
16551
  gl.shaderSource(this._fragmentShader, fragmentShaderStr);
16221
16552
  gl.compileShader(this._fragmentShader);
16222
16553
  if (!gl.getShaderParameter(this._fragmentShader, gl.COMPILE_STATUS)) {
16223
- alert(gl.getShaderInfoLog(this._fragmentShader) || 'Fragment shader compile error');
16554
+ alert(gl.getShaderInfoLog(this._fragmentShader) ||
16555
+ "Fragment shader compile error");
16224
16556
  return;
16225
16557
  }
16226
16558
  gl.attachShader(this.shaderProgram, this._fragmentShader);
16227
16559
  gl.linkProgram(this.shaderProgram);
16228
16560
  if (!gl.getProgramParameter(this.shaderProgram, gl.LINK_STATUS)) {
16229
- alert('Could not initialise shaders');
16561
+ alert("Could not initialise shaders");
16230
16562
  }
16231
16563
  gl.useProgram(this.shaderProgram);
16232
16564
  }
16565
+ setTextureDataMode(samplerIndex, fits, min, max) {
16566
+ if (samplerIndex < 0 || samplerIndex >= 8) {
16567
+ throw new Error(`Invalid HiPS sampler index: ${samplerIndex}`);
16568
+ }
16569
+ const gl = this._webgl;
16570
+ const modeLocation = this.locations.textureMode[samplerIndex];
16571
+ if (modeLocation) {
16572
+ gl.uniform1i(modeLocation, fits ? 1 : 0);
16573
+ }
16574
+ if (!fits) {
16575
+ return;
16576
+ }
16577
+ if (min === undefined ||
16578
+ max === undefined ||
16579
+ !Number.isFinite(min) ||
16580
+ !Number.isFinite(max) ||
16581
+ max <= min) {
16582
+ throw new Error("Invalid FITS display range.");
16583
+ }
16584
+ const minLocation = this.locations.dataMin[samplerIndex];
16585
+ const maxLocation = this.locations.dataMax[samplerIndex];
16586
+ if (minLocation) {
16587
+ gl.uniform1f(minLocation, min);
16588
+ }
16589
+ if (maxLocation) {
16590
+ gl.uniform1f(maxLocation, max);
16591
+ }
16592
+ }
16233
16593
  enableShaders(pMatrix, vMatrix, mMatrix, colorMapIdx) {
16234
- // const gl = global.gl as GL
16594
+ // const gl = global.gl
16235
16595
  const gl = this._webgl;
16236
16596
  gl.useProgram(this.shaderProgram);
16237
16597
  this.locations.pMatrix = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.m_perspective);
16238
16598
  this.locations.mMatrix = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.m_model);
16239
16599
  this.locations.vMatrix = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.m_view);
16240
- this.locations.sampler = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.sampler);
16241
- this.locations.textureAlpha = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.factor);
16242
16600
  this.locations.clorMapIdx = gl.getUniformLocation(this.shaderProgram, this.gl_uniforms.colormapIdx);
16243
- // NEW
16244
- // if (this.locations.clorMapIdx) {
16245
- gl.uniform1i(this.locations.clorMapIdx, colorMapIdx);
16246
- // }
16247
- // Make sampler explicit: we always use TEXTURE0 in your draw code
16248
- if (this.locations.sampler) {
16249
- gl.uniform1i(this.locations.sampler, 0);
16601
+ for (let i = 0; i < 8; i++) {
16602
+ this.locations.samplers[i] = gl.getUniformLocation(this.shaderProgram, `uSampler${i}`);
16603
+ this.locations.textureAlpha[i] = gl.getUniformLocation(this.shaderProgram, `uFactor${i}`);
16604
+ this.locations.textureMode[i] = gl.getUniformLocation(this.shaderProgram, `uTextureMode${i}`);
16605
+ this.locations.dataMin[i] = gl.getUniformLocation(this.shaderProgram, `uDataMin${i}`);
16606
+ this.locations.dataMax[i] = gl.getUniformLocation(this.shaderProgram, `uDataMax${i}`);
16607
+ if (this.locations.samplers[i]) {
16608
+ gl.uniform1i(this.locations.samplers[i], i);
16609
+ }
16250
16610
  }
16251
- // END NEW
16611
+ gl.uniform1i(this.locations.clorMapIdx, colorMapIdx);
16252
16612
  this.locations.vertexPositionAttribute = gl.getAttribLocation(this.shaderProgram, this.gl_attributes.vertex_pos);
16253
16613
  this.locations.textureCoordAttribute = gl.getAttribLocation(this.shaderProgram, this.gl_attributes.text_coords);
16254
- if (colorMapIdx >= 2 && this._UBO_colorMapBuffer && this._colorMapBlockIndex !== null) {
16614
+ if (colorMapIdx >= 2 &&
16615
+ this._UBO_colorMapBuffer &&
16616
+ this._colorMapBlockIndex !== null) {
16255
16617
  gl.uniformBlockBinding(this.shaderProgram, this._colorMapBlockIndex, 0);
16256
16618
  gl.bindBuffer(gl.UNIFORM_BUFFER, this._UBO_colorMapBuffer);
16257
16619
  let currentColorMap;
@@ -16624,15 +16986,6 @@ class ShaderManager {
16624
16986
 
16625
16987
  in vec2 vTextureCoord;
16626
16988
 
16627
- uniform sampler2D uSampler0;
16628
- uniform sampler2D uSampler1;
16629
- uniform sampler2D uSampler2;
16630
- uniform sampler2D uSampler3;
16631
- uniform sampler2D uSampler4;
16632
- uniform sampler2D uSampler5;
16633
- uniform sampler2D uSampler6;
16634
- uniform sampler2D uSampler7;
16635
-
16636
16989
  uniform float uFactor0;
16637
16990
  uniform float uFactor1;
16638
16991
  uniform float uFactor2;
@@ -16642,23 +16995,53 @@ class ShaderManager {
16642
16995
  uniform float uFactor6;
16643
16996
  uniform float uFactor7;
16644
16997
 
16998
+ ${ShaderManager.hipsSamplersGLSL()}
16999
+
16645
17000
  out vec4 fragColor;
16646
17001
 
16647
17002
  void main() {
16648
17003
  vec3 finalColor = vec3(0.0);
16649
17004
 
16650
- if (uFactor0 >= 0.0){
16651
- vec4 mycolor;
16652
- #if __VERSION__ > 120
16653
- vec4 color0 = texture(uSampler0, vTextureCoord);
16654
- #else
16655
- vec4 color0 = texture2D(uSampler0, vTextureCoord);
16656
- #endif
16657
- mycolor = color0;
16658
- finalColor += mycolor.rgb * uFactor0;
16659
- } else if (uFactor7 >= 0.0){
16660
- finalColor = vec3(1.0, 0.0, 0.0);
17005
+ if (uFactor0 >= 0.0) {
17006
+ finalColor +=
17007
+ sampleHiPSTexture0(vTextureCoord).rgb * uFactor0;
17008
+ }
17009
+
17010
+ if (uFactor1 >= 0.0) {
17011
+ finalColor +=
17012
+ sampleHiPSTexture1(vTextureCoord).rgb * uFactor1;
17013
+ }
17014
+
17015
+ if (uFactor2 >= 0.0) {
17016
+ finalColor +=
17017
+ sampleHiPSTexture2(vTextureCoord).rgb * uFactor2;
16661
17018
  }
17019
+
17020
+ if (uFactor3 >= 0.0) {
17021
+ finalColor +=
17022
+ sampleHiPSTexture3(vTextureCoord).rgb * uFactor3;
17023
+ }
17024
+
17025
+ if (uFactor4 >= 0.0) {
17026
+ finalColor +=
17027
+ sampleHiPSTexture4(vTextureCoord).rgb * uFactor4;
17028
+ }
17029
+
17030
+ if (uFactor5 >= 0.0) {
17031
+ finalColor +=
17032
+ sampleHiPSTexture5(vTextureCoord).rgb * uFactor5;
17033
+ }
17034
+
17035
+ if (uFactor6 >= 0.0) {
17036
+ finalColor +=
17037
+ sampleHiPSTexture6(vTextureCoord).rgb * uFactor6;
17038
+ }
17039
+
17040
+ if (uFactor7 >= 0.0) {
17041
+ finalColor +=
17042
+ sampleHiPSTexture7(vTextureCoord).rgb * uFactor7;
17043
+ }
17044
+
16662
17045
  fragColor = vec4(finalColor, 1.0);
16663
17046
  }`;
16664
17047
  }
@@ -16668,15 +17051,6 @@ class ShaderManager {
16668
17051
 
16669
17052
  in vec2 vTextureCoord;
16670
17053
 
16671
- uniform sampler2D uSampler0;
16672
- uniform sampler2D uSampler1;
16673
- uniform sampler2D uSampler2;
16674
- uniform sampler2D uSampler3;
16675
- uniform sampler2D uSampler4;
16676
- uniform sampler2D uSampler5;
16677
- uniform sampler2D uSampler6;
16678
- uniform sampler2D uSampler7;
16679
-
16680
17054
  uniform float uFactor0;
16681
17055
  uniform float uFactor1;
16682
17056
  uniform float uFactor2;
@@ -16686,76 +17060,61 @@ class ShaderManager {
16686
17060
  uniform float uFactor6;
16687
17061
  uniform float uFactor7;
16688
17062
 
17063
+ ${ShaderManager.hipsSamplersGLSL()}
17064
+
16689
17065
  out vec4 fragColor;
16690
17066
 
16691
17067
  void main() {
16692
17068
  vec3 finalColor = vec3(0.0);
16693
17069
 
16694
- if (uFactor0 >= 0.0){
16695
- #if __VERSION__ > 120
16696
- vec4 color0 = texture(uSampler0, vTextureCoord);
16697
- #else
16698
- vec4 color0 = texture2D(uSampler0, vTextureCoord);
16699
- #endif
16700
- float gray = 0.21 * color0.r + 0.71 * color0.g + 0.07 * color0.b;
16701
- finalColor = color0.rgb * (1.0 - uFactor0) + vec3(gray) * uFactor0;
17070
+ if (uFactor0 >= 0.0) {
17071
+ vec4 color0 = sampleHiPSTexture0(vTextureCoord);
17072
+
17073
+ float gray =
17074
+ 0.21 * color0.r +
17075
+ 0.71 * color0.g +
17076
+ 0.07 * color0.b;
17077
+
17078
+ finalColor =
17079
+ color0.rgb * (1.0 - uFactor0) +
17080
+ vec3(gray) * uFactor0;
16702
17081
  }
16703
- if (uFactor1 >= 0.0){
16704
- #if __VERSION__ > 120
16705
- vec4 color1 = texture(uSampler1, vTextureCoord);
16706
- #else
16707
- vec4 color1 = texture2D(uSampler1, vTextureCoord);
16708
- #endif
17082
+
17083
+ if (uFactor1 >= 0.0) {
17084
+ vec4 color1 = sampleHiPSTexture1(vTextureCoord);
16709
17085
  finalColor += color1.rgb * uFactor1;
16710
17086
  }
16711
- if (uFactor2 >= 0.0){
16712
- #if __VERSION__ > 120
16713
- vec4 color2 = texture(uSampler2, vTextureCoord);
16714
- #else
16715
- vec4 color2 = texture2D(uSampler2, vTextureCoord);
16716
- #endif
17087
+
17088
+ if (uFactor2 >= 0.0) {
17089
+ vec4 color2 = sampleHiPSTexture2(vTextureCoord);
16717
17090
  finalColor += color2.rgb * uFactor2;
16718
17091
  }
16719
- if (uFactor3 >= 0.0){
16720
- #if __VERSION__ > 120
16721
- vec4 color3 = texture(uSampler3, vTextureCoord);
16722
- #else
16723
- vec4 color3 = texture2D(uSampler3, vTextureCoord);
16724
- #endif
17092
+
17093
+ if (uFactor3 >= 0.0) {
17094
+ vec4 color3 = sampleHiPSTexture3(vTextureCoord);
16725
17095
  finalColor += color3.rgb * uFactor3;
16726
17096
  }
16727
- if (uFactor4 >= 0.0){
16728
- #if __VERSION__ > 120
16729
- vec4 color4 = texture(uSampler4, vTextureCoord);
16730
- #else
16731
- vec4 color4 = texture2D(uSampler4, vTextureCoord);
16732
- #endif
17097
+
17098
+ if (uFactor4 >= 0.0) {
17099
+ vec4 color4 = sampleHiPSTexture4(vTextureCoord);
16733
17100
  finalColor += color4.rgb * uFactor4;
16734
17101
  }
16735
- if (uFactor5 >= 0.0){
16736
- #if __VERSION__ > 120
16737
- vec4 color5 = texture(uSampler5, vTextureCoord);
16738
- #else
16739
- vec4 color5 = texture2D(uSampler5, vTextureCoord);
16740
- #endif
17102
+
17103
+ if (uFactor5 >= 0.0) {
17104
+ vec4 color5 = sampleHiPSTexture5(vTextureCoord);
16741
17105
  finalColor += color5.rgb * uFactor5;
16742
17106
  }
16743
- if (uFactor6 >= 0.0){
16744
- #if __VERSION__ > 120
16745
- vec4 color6 = texture(uSampler6, vTextureCoord);
16746
- #else
16747
- vec4 color6 = texture2D(uSampler6, vTextureCoord);
16748
- #endif
17107
+
17108
+ if (uFactor6 >= 0.0) {
17109
+ vec4 color6 = sampleHiPSTexture6(vTextureCoord);
16749
17110
  finalColor += color6.rgb * uFactor6;
16750
17111
  }
16751
- if (uFactor7 >= 0.0){
16752
- #if __VERSION__ > 120
16753
- vec4 color7 = texture(uSampler7, vTextureCoord);
16754
- #else
16755
- vec4 color7 = texture2D(uSampler7, vTextureCoord);
16756
- #endif
17112
+
17113
+ if (uFactor7 >= 0.0) {
17114
+ vec4 color7 = sampleHiPSTexture7(vTextureCoord);
16757
17115
  finalColor += color7.rgb * uFactor7;
16758
17116
  }
17117
+
16759
17118
  fragColor = vec4(finalColor, 1.0);
16760
17119
  }`;
16761
17120
  }
@@ -16765,38 +17124,140 @@ class ShaderManager {
16765
17124
 
16766
17125
  in vec2 vTextureCoord;
16767
17126
 
16768
- // UBO
16769
17127
  layout (std140) uniform colormap {
16770
17128
  float r_palette[256];
16771
17129
  float g_palette[256];
16772
17130
  float b_palette[256];
16773
17131
  };
16774
17132
 
16775
- uniform sampler2D uSampler0;
16776
17133
  uniform float uFactor0;
17134
+ uniform float uFactor1;
17135
+ uniform float uFactor2;
17136
+ uniform float uFactor3;
17137
+ uniform float uFactor4;
17138
+ uniform float uFactor5;
17139
+ uniform float uFactor6;
17140
+ uniform float uFactor7;
17141
+
17142
+ ${ShaderManager.hipsSamplersGLSL()}
16777
17143
 
16778
17144
  out vec4 fragColor;
16779
17145
 
16780
- void main() {
16781
- #if __VERSION__ > 120
16782
- vec4 color0 = texture(uSampler0, vTextureCoord);
16783
- #else
16784
- vec4 color0 = texture2D(uSampler0, vTextureCoord);
16785
- #endif
17146
+ vec3 applyColorMap(vec4 color) {
17147
+ int x = int(clamp(color.r, 0.0, 1.0) * 255.0);
17148
+ int y = int(clamp(color.g, 0.0, 1.0) * 255.0);
17149
+ int z = int(clamp(color.b, 0.0, 1.0) * 255.0);
16786
17150
 
16787
- int x = int(color0.r * 255.0);
16788
17151
  float px = r_palette[x] / 256.0;
16789
-
16790
- int y = int(color0.g * 255.0);
16791
17152
  float py = g_palette[y] / 256.0;
16792
-
16793
- int z = int(color0.b * 255.0);
16794
17153
  float pz = b_palette[z] / 256.0;
16795
17154
 
16796
- // uFactor0 reserved for future blending if needed
16797
- fragColor = vec4(px, py, pz, 1.0);
17155
+ return vec3(px, py, pz);
17156
+ }
17157
+
17158
+ void main() {
17159
+ vec3 finalColor = vec3(0.0);
17160
+
17161
+ if (uFactor0 >= 0.0) {
17162
+ finalColor +=
17163
+ applyColorMap(
17164
+ sampleHiPSTexture0(vTextureCoord)
17165
+ ) * uFactor0;
17166
+ }
17167
+
17168
+ if (uFactor1 >= 0.0) {
17169
+ finalColor +=
17170
+ applyColorMap(
17171
+ sampleHiPSTexture1(vTextureCoord)
17172
+ ) * uFactor1;
17173
+ }
17174
+
17175
+ if (uFactor2 >= 0.0) {
17176
+ finalColor +=
17177
+ applyColorMap(
17178
+ sampleHiPSTexture2(vTextureCoord)
17179
+ ) * uFactor2;
17180
+ }
17181
+
17182
+ if (uFactor3 >= 0.0) {
17183
+ finalColor +=
17184
+ applyColorMap(
17185
+ sampleHiPSTexture3(vTextureCoord)
17186
+ ) * uFactor3;
17187
+ }
17188
+
17189
+ if (uFactor4 >= 0.0) {
17190
+ finalColor +=
17191
+ applyColorMap(
17192
+ sampleHiPSTexture4(vTextureCoord)
17193
+ ) * uFactor4;
17194
+ }
17195
+
17196
+ if (uFactor5 >= 0.0) {
17197
+ finalColor +=
17198
+ applyColorMap(
17199
+ sampleHiPSTexture5(vTextureCoord)
17200
+ ) * uFactor5;
17201
+ }
17202
+
17203
+ if (uFactor6 >= 0.0) {
17204
+ finalColor +=
17205
+ applyColorMap(
17206
+ sampleHiPSTexture6(vTextureCoord)
17207
+ ) * uFactor6;
17208
+ }
17209
+
17210
+ if (uFactor7 >= 0.0) {
17211
+ finalColor +=
17212
+ applyColorMap(
17213
+ sampleHiPSTexture7(vTextureCoord)
17214
+ ) * uFactor7;
17215
+ }
17216
+
17217
+ fragColor = vec4(finalColor, 1.0);
16798
17218
  }`;
16799
17219
  }
17220
+ static hipsSamplerGLSL(index) {
17221
+ return `
17222
+ uniform sampler2D uSampler${index};
17223
+ uniform int uTextureMode${index};
17224
+ uniform float uDataMin${index};
17225
+ uniform float uDataMax${index};
17226
+
17227
+ vec4 sampleHiPSTexture${index}(vec2 uv) {
17228
+ vec4 color = texture(uSampler${index}, uv);
17229
+
17230
+ // JPG / PNG
17231
+ if (uTextureMode${index} == 0) {
17232
+ return color;
17233
+ }
17234
+
17235
+ // FITS physical value stored in red channel
17236
+ float value = color.r;
17237
+
17238
+ if (isnan(value)) {
17239
+ discard;
17240
+ }
17241
+
17242
+ float normalized = clamp(
17243
+ (value - uDataMin${index}) /
17244
+ (uDataMax${index} - uDataMin${index}),
17245
+ 0.0,
17246
+ 1.0
17247
+ );
17248
+
17249
+ return vec4(
17250
+ normalized,
17251
+ normalized,
17252
+ normalized,
17253
+ 1.0
17254
+ );
17255
+ }
17256
+ `;
17257
+ }
17258
+ static hipsSamplersGLSL() {
17259
+ return Array.from({ length: 8 }, (_, index) => ShaderManager.hipsSamplerGLSL(index)).join("\n");
17260
+ }
16800
17261
  }
16801
17262
  exports["default"] = ShaderManager;
16802
17263
 
@@ -18467,6 +18928,55 @@ class XYZRayPickingUtils {
18467
18928
  exports["default"] = XYZRayPickingUtils;
18468
18929
 
18469
18930
 
18931
+ /***/ },
18932
+
18933
+ /***/ 8611
18934
+ (module) {
18935
+
18936
+ module.exports = require("http");
18937
+
18938
+ /***/ },
18939
+
18940
+ /***/ 5692
18941
+ (module) {
18942
+
18943
+ module.exports = require("https");
18944
+
18945
+ /***/ },
18946
+
18947
+ /***/ 1455
18948
+ (module) {
18949
+
18950
+ module.exports = require("node:fs/promises");
18951
+
18952
+ /***/ },
18953
+
18954
+ /***/ 4876
18955
+ (module) {
18956
+
18957
+ module.exports = require("punycode");
18958
+
18959
+ /***/ },
18960
+
18961
+ /***/ 2203
18962
+ (module) {
18963
+
18964
+ module.exports = require("stream");
18965
+
18966
+ /***/ },
18967
+
18968
+ /***/ 7016
18969
+ (module) {
18970
+
18971
+ module.exports = require("url");
18972
+
18973
+ /***/ },
18974
+
18975
+ /***/ 3106
18976
+ (module) {
18977
+
18978
+ module.exports = require("zlib");
18979
+
18470
18980
  /***/ },
18471
18981
 
18472
18982
  /***/ 4851
@@ -19265,76 +19775,1760 @@ function findCircleThroughTwoPoints(points, q1, q2) {
19265
19775
 
19266
19776
 
19267
19777
 
19268
- /***/ }
19778
+ /***/ },
19269
19779
 
19270
- /******/ });
19271
- /************************************************************************/
19272
- /******/ // The module cache
19273
- /******/ const __webpack_module_cache__ = {};
19274
- /******/
19275
- /******/ // The require function
19276
- /******/ function __webpack_require__(moduleId) {
19277
- /******/ // Check if module is in cache
19278
- /******/ const cachedModule = __webpack_module_cache__[moduleId];
19279
- /******/ if (cachedModule !== undefined) {
19280
- /******/ return cachedModule.exports;
19281
- /******/ }
19282
- /******/ // Create a new module (and put it into the cache)
19283
- /******/ const module = __webpack_module_cache__[moduleId] = {
19284
- /******/ // no module.id needed
19285
- /******/ // no module.loaded needed
19286
- /******/ exports: {}
19287
- /******/ };
19288
- /******/
19289
- /******/ // Execute the module function
19290
- /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
19291
- /******/
19292
- /******/ // Return the exports of the module
19293
- /******/ return module.exports;
19294
- /******/ }
19295
- /******/
19296
- /************************************************************************/
19297
- /******/ /* webpack/runtime/define property getters */
19298
- /******/ (() => {
19299
- /******/ // define getter/value functions for harmony exports
19300
- /******/ __webpack_require__.d = (exports, definition) => {
19301
- /******/ if(Array.isArray(definition)) {
19302
- /******/ var i = 0;
19303
- /******/ while(i < definition.length) {
19304
- /******/ var key = definition[i++];
19305
- /******/ var binding = definition[i++];
19306
- /******/ if(!__webpack_require__.o(exports, key)) {
19307
- /******/ if(binding === 0) {
19308
- /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
19309
- /******/ } else {
19310
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
19311
- /******/ }
19312
- /******/ } else if(binding === 0) { i++; }
19313
- /******/ }
19314
- /******/ } else {
19315
- /******/ for(var key in definition) {
19316
- /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
19317
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
19318
- /******/ }
19319
- /******/ }
19320
- /******/ }
19321
- /******/ };
19322
- /******/ })();
19323
- /******/
19324
- /******/ /* webpack/runtime/hasOwnProperty shorthand */
19325
- /******/ (() => {
19326
- /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
19327
- /******/ })();
19328
- /******/
19329
- /******/ /* webpack/runtime/make namespace object */
19330
- /******/ (() => {
19331
- /******/ // define __esModule on exports
19332
- /******/ __webpack_require__.r = (exports) => {
19333
- /******/ if(Symbol.toStringTag) {
19334
- /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
19335
- /******/ }
19336
- /******/ Object.defineProperty(exports, '__esModule', { value: true });
19780
+ /***/ 4971
19781
+ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
19782
+
19783
+
19784
+ // EXPORTS
19785
+ __webpack_require__.d(__webpack_exports__, {
19786
+ FITSHeaderManager: () => (/* reexport */ FITSHeaderManager),
19787
+ FITSParser: () => (/* reexport */ FITSParser)
19788
+ });
19789
+
19790
+ // UNUSED EXPORTS: AsciiTableHDU, BinaryTableHDU, FITSFile, FITSHDU, FITSHeaderItem, FITSWriter, ImageHDU, ParseHeader, ParsePayload, PrimaryHDU
19791
+
19792
+ ;// ./node_modules/jsfitsio/lib-esm/model/FITSHeaderItem.js
19793
+ /**
19794
+ * Summary. (bla bla bla)
19795
+ *
19796
+ * Description. (bla bla bla)
19797
+ *
19798
+ * @link github https://github.com/fab77/FITSParser
19799
+ * @author Fabrizio Giordano <fabriziogiordano77@gmail.com>
19800
+ */
19801
+ class FITSHeaderItem {
19802
+ _key = "";
19803
+ _value = "";
19804
+ _comment = "";
19805
+ constructor(key, value, comment) {
19806
+ this._key = key;
19807
+ this._value = value;
19808
+ this._comment = comment;
19809
+ }
19810
+ get key() {
19811
+ return this._key;
19812
+ }
19813
+ get comment() {
19814
+ return this._comment;
19815
+ }
19816
+ get value() {
19817
+ return this._value;
19818
+ }
19819
+ }
19820
+ //# sourceMappingURL=FITSHeaderItem.js.map
19821
+ ;// ./node_modules/jsfitsio/lib-esm/model/FITSHeaderManager.js
19822
+
19823
+ class FITSHeaderManager {
19824
+ static SIMPLE = "SIMPLE";
19825
+ static BITPIX = "BITPIX";
19826
+ static BZERO = "BZERO";
19827
+ static BSCALE = "BSCALE";
19828
+ static BLANK = "BLANK";
19829
+ static NAXIS = "NAXIS";
19830
+ static NAXIS1 = "NAXIS1";
19831
+ static NAXIS2 = "NAXIS2";
19832
+ static DATAMIN = "DATAMIN";
19833
+ static DATAMAX = "DATAMAX";
19834
+ static CRVAL1 = "CRVAL1";
19835
+ static CRVAL2 = "CRVAL2";
19836
+ static CTYPE1 = "CTYPE1";
19837
+ static CTYPE2 = "CTYPE2";
19838
+ static CRPIX1 = "CRPIX1";
19839
+ static CRPIX2 = "CRPIX2";
19840
+ static ORIGIN = "ORIGIN";
19841
+ static COMMENT = "COMMENT";
19842
+ static XTENSION = "XTENSION";
19843
+ static PCOUNT = "PCOUNT";
19844
+ static GCOUNT = "GCOUNT";
19845
+ static TFIELDS = "TFIELDS";
19846
+ static TFORM = "TFORM";
19847
+ static TTYPE = "TTYPE";
19848
+ static TUNIT = "TUNIT";
19849
+ static TSCAL = "TSCAL";
19850
+ static TZERO = "TZERO";
19851
+ static TNULL = "TNULL";
19852
+ static TBCOL = "TBCOL";
19853
+ items = [];
19854
+ constructor(initializeDefaults = true) {
19855
+ if (!initializeDefaults) {
19856
+ return;
19857
+ }
19858
+ this.items[0] = new FITSHeaderItem(FITSHeaderManager.SIMPLE, "T", "");
19859
+ this.items[1] = new FITSHeaderItem(FITSHeaderManager.BITPIX, "", "");
19860
+ this.items[2] = new FITSHeaderItem(FITSHeaderManager.NAXIS, 2, "");
19861
+ this.items[3] = new FITSHeaderItem(FITSHeaderManager.NAXIS1, "", "");
19862
+ this.items[4] = new FITSHeaderItem(FITSHeaderManager.NAXIS2, "", "");
19863
+ }
19864
+ // insert(item: FITSHeaderItem, position?: number): void {
19865
+ insert(item) {
19866
+ if (item.key === FITSHeaderManager.SIMPLE) {
19867
+ // this.items.splice(0, 0, item);
19868
+ this.items[0] = item;
19869
+ }
19870
+ else if (item.key === FITSHeaderManager.BITPIX) {
19871
+ // this.items.splice(1, 0, item);
19872
+ this.items[1] = item;
19873
+ }
19874
+ else if (item.key === FITSHeaderManager.NAXIS) {
19875
+ // this.items.splice(2, 0, item);
19876
+ this.items[2] = item;
19877
+ }
19878
+ else if (item.key === FITSHeaderManager.NAXIS1) {
19879
+ // this.items.splice(3, 0, item);
19880
+ this.items[3] = item;
19881
+ }
19882
+ else if (item.key === FITSHeaderManager.NAXIS2) {
19883
+ // this.items.splice(4, 0, item);
19884
+ this.items[4] = item;
19885
+ }
19886
+ else {
19887
+ this.items.push(item);
19888
+ }
19889
+ // if (position !== undefined && position >= 0 && position <= this.items.length) {
19890
+ // this.items.splice(position, 0, item);
19891
+ // } else {
19892
+ // this.items.push(item);
19893
+ // }
19894
+ }
19895
+ getItems() {
19896
+ return this.items;
19897
+ }
19898
+ remove(key) {
19899
+ this.items = this.items.filter((item) => item.key !== key);
19900
+ }
19901
+ findById(key) {
19902
+ const item = this.items.find((item) => item.key === key);
19903
+ if (!item) {
19904
+ return null;
19905
+ }
19906
+ return item;
19907
+ }
19908
+ static tableFieldKey(prefix, index) {
19909
+ if (!Number.isInteger(index) || index < 1) {
19910
+ throw new RangeError(`FITS table field index must be >= 1, received ${index}.`);
19911
+ }
19912
+ return `${prefix}${index}`;
19913
+ }
19914
+ static naxisKey(axis) {
19915
+ if (!Number.isInteger(axis) || axis < 1) {
19916
+ throw new RangeError(`FITS axis must be a positive integer, received ${axis}.`);
19917
+ }
19918
+ return `NAXIS${axis}`;
19919
+ }
19920
+ static getFITSItemStringValue(header, key) {
19921
+ const item = header.findById(key);
19922
+ if (!item) {
19923
+ return null;
19924
+ }
19925
+ return String(item.value).trim().replace(/^'/, "").replace(/'$/, "").trim();
19926
+ }
19927
+ }
19928
+ //# sourceMappingURL=FITSHeaderManager.js.map
19929
+ ;// external "fs"
19930
+ const external_fs_namespaceObject = require("fs");
19931
+ ;// ./node_modules/jsfitsio/lib-esm/FITSHeaderWriter.js
19932
+ class FITSHeaderWriter {
19933
+ static BLOCK_SIZE = 2880;
19934
+ static CARD_SIZE = 80;
19935
+ static INTEGER_KEYWORDS = new Set([
19936
+ "BITPIX",
19937
+ "NAXIS",
19938
+ "PCOUNT",
19939
+ "GCOUNT",
19940
+ ]);
19941
+ static LOGICAL_KEYWORDS = new Set(["SIMPLE", "EXTEND"]);
19942
+ static serialize(header, primary) {
19943
+ const items = header.getItems();
19944
+ const map = new Map(items.map((item) => [item.key.toUpperCase(), item]));
19945
+ const cards = [];
19946
+ FITSHeaderWriter.appendMandatoryCards(cards, map, primary);
19947
+ FITSHeaderWriter.appendRemainingCards(cards, items);
19948
+ cards.push(FITSHeaderWriter.card80("END"));
19949
+ return FITSHeaderWriter.encodeAndPad(cards);
19950
+ }
19951
+ static appendMandatoryCards(cards, map, primary) {
19952
+ if (primary) {
19953
+ const simple = map.get("SIMPLE");
19954
+ if (!simple) {
19955
+ throw new Error("Missing mandatory SIMPLE card in Primary HDU");
19956
+ }
19957
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("SIMPLE", simple.value, simple.comment));
19958
+ }
19959
+ else {
19960
+ const xtension = map.get("XTENSION");
19961
+ if (!xtension) {
19962
+ throw new Error("Missing mandatory XTENSION card in extension HDU");
19963
+ }
19964
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("XTENSION", xtension.value, xtension.comment));
19965
+ }
19966
+ const bitpix = map.get("BITPIX");
19967
+ if (!bitpix) {
19968
+ throw new Error("Missing mandatory BITPIX card");
19969
+ }
19970
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("BITPIX", bitpix.value, bitpix.comment));
19971
+ const naxis = map.get("NAXIS");
19972
+ if (!naxis) {
19973
+ throw new Error("Missing mandatory NAXIS card");
19974
+ }
19975
+ const nAxes = Number(naxis.value);
19976
+ if (!Number.isInteger(nAxes) || nAxes < 0) {
19977
+ throw new Error(`Invalid NAXIS value: ${naxis.value}`);
19978
+ }
19979
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("NAXIS", nAxes, naxis.comment));
19980
+ for (let axis = 1; axis <= nAxes; axis++) {
19981
+ const key = `NAXIS${axis}`;
19982
+ const item = map.get(key);
19983
+ if (!item) {
19984
+ throw new Error(`Missing mandatory ${key} card`);
19985
+ }
19986
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment(key, item.value, item.comment));
19987
+ }
19988
+ if (!primary) {
19989
+ const pcount = map.get("PCOUNT");
19990
+ const gcount = map.get("GCOUNT");
19991
+ if (!pcount) {
19992
+ throw new Error("Missing mandatory PCOUNT card in extension HDU");
19993
+ }
19994
+ if (!gcount) {
19995
+ throw new Error("Missing mandatory GCOUNT card in extension HDU");
19996
+ }
19997
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("PCOUNT", pcount.value, pcount.comment));
19998
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("GCOUNT", gcount.value, gcount.comment));
19999
+ }
20000
+ if (primary) {
20001
+ const extend = map.get("EXTEND");
20002
+ if (extend) {
20003
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment("EXTEND", extend.value, extend.comment));
20004
+ }
20005
+ }
20006
+ }
20007
+ static appendRemainingCards(cards, items) {
20008
+ for (const item of items) {
20009
+ const key = item.key.toUpperCase();
20010
+ if (key === "SIMPLE" ||
20011
+ key === "XTENSION" ||
20012
+ key === "BITPIX" ||
20013
+ key === "NAXIS" ||
20014
+ /^NAXIS\d+$/.test(key) ||
20015
+ key === "PCOUNT" ||
20016
+ key === "GCOUNT" ||
20017
+ key === "EXTEND" ||
20018
+ key === "END") {
20019
+ continue;
20020
+ }
20021
+ cards.push(...FITSHeaderWriter.makeKeywordWithComment(item.key, item.value, item.comment));
20022
+ }
20023
+ }
20024
+ static makeKeywordWithComment(key, value, comment) {
20025
+ const normalized = key.toUpperCase();
20026
+ if (normalized === "END") {
20027
+ return [FITSHeaderWriter.card80("END")];
20028
+ }
20029
+ if (normalized === "COMMENT" || normalized === "HISTORY") {
20030
+ return FITSHeaderWriter.makeCommentCards(normalized, String(value ?? comment ?? ""));
20031
+ }
20032
+ let base = FITSHeaderWriter.keyword(normalized) +
20033
+ FITSHeaderWriter.valueField20(normalized, value);
20034
+ if (!comment || comment.length === 0) {
20035
+ return [FITSHeaderWriter.card80(base)];
20036
+ }
20037
+ const addition = ` / ${comment}`;
20038
+ const spaceLeft = FITSHeaderWriter.CARD_SIZE - base.length;
20039
+ if (spaceLeft <= 0) {
20040
+ return [
20041
+ FITSHeaderWriter.card80(base),
20042
+ ...FITSHeaderWriter.makeCommentCards("COMMENT", comment),
20043
+ ];
20044
+ }
20045
+ base += addition.slice(0, spaceLeft);
20046
+ const overflow = addition.slice(spaceLeft).replace(/^\s*\/\s*/, "");
20047
+ if (overflow.length === 0) {
20048
+ return [FITSHeaderWriter.card80(base)];
20049
+ }
20050
+ return [
20051
+ FITSHeaderWriter.card80(base),
20052
+ ...FITSHeaderWriter.makeCommentCards("COMMENT", overflow),
20053
+ ];
20054
+ }
20055
+ static makeCommentCards(kind, text) {
20056
+ const prefix = FITSHeaderWriter.keyword(kind);
20057
+ const width = FITSHeaderWriter.CARD_SIZE - prefix.length;
20058
+ const value = String(text ?? "");
20059
+ if (value.length === 0) {
20060
+ return [FITSHeaderWriter.card80(prefix)];
20061
+ }
20062
+ const cards = [];
20063
+ for (let offset = 0; offset < value.length; offset += width) {
20064
+ cards.push(FITSHeaderWriter.card80(prefix + value.slice(offset, offset + width)));
20065
+ }
20066
+ return cards;
20067
+ }
20068
+ static valueField20(key, value) {
20069
+ if (FITSHeaderWriter.LOGICAL_KEYWORDS.has(key)) {
20070
+ const logical = value === true || value === "T" || value === "t" ? "T" : "F";
20071
+ return `= ${logical.padStart(20, " ")}`;
20072
+ }
20073
+ if (FITSHeaderWriter.INTEGER_KEYWORDS.has(key) || /^NAXIS\d+$/.test(key)) {
20074
+ const number = Number(value);
20075
+ if (!Number.isFinite(number) || !Number.isInteger(number)) {
20076
+ throw new Error(`FITS header: ${key} must be an integer, got ${value}`);
20077
+ }
20078
+ return `= ${String(number).padStart(20, " ")}`;
20079
+ }
20080
+ if (typeof value === "number") {
20081
+ let encoded = Number.isInteger(value)
20082
+ ? String(value)
20083
+ : value.toExponential(10).replace("e", "E");
20084
+ if (encoded.length > 20) {
20085
+ encoded = value.toExponential(8).replace("e", "E");
20086
+ }
20087
+ return `= ${encoded.padStart(20, " ")}`;
20088
+ }
20089
+ if (typeof value === "string") {
20090
+ return `= ${FITSHeaderWriter.quoteFitsString(value)}`;
20091
+ }
20092
+ return "";
20093
+ }
20094
+ static quoteFitsString(value) {
20095
+ const unquoted = value.replace(/^'+|'+$/g, "");
20096
+ const escaped = unquoted.replace(/'/g, "''");
20097
+ return `'${escaped}'`;
20098
+ }
20099
+ static keyword(value) {
20100
+ return (value ?? "").toUpperCase().padEnd(8, " ").slice(0, 8);
20101
+ }
20102
+ static card80(value) {
20103
+ if (value.length >= FITSHeaderWriter.CARD_SIZE) {
20104
+ return value.slice(0, FITSHeaderWriter.CARD_SIZE);
20105
+ }
20106
+ return value.padEnd(FITSHeaderWriter.CARD_SIZE, " ");
20107
+ }
20108
+ static encodeAndPad(cards) {
20109
+ let header = cards.join("");
20110
+ const remainder = header.length % FITSHeaderWriter.BLOCK_SIZE;
20111
+ if (remainder !== 0) {
20112
+ header += " ".repeat(FITSHeaderWriter.BLOCK_SIZE - remainder);
20113
+ }
20114
+ return new TextEncoder().encode(header);
20115
+ }
20116
+ }
20117
+ //# sourceMappingURL=FITSHeaderWriter.js.map
20118
+ ;// ./node_modules/jsfitsio/lib-esm/FITSWriter.js
20119
+ /**
20120
+ * FITS serialization and file writing support.
20121
+ *
20122
+ * FITSWriter provides two serialization APIs:
20123
+ *
20124
+ * - The jsfitsio 3.x API serializes the FITSFile/HDU data model,
20125
+ * including PrimaryHDU, ImageHDU, BinaryTableHDU and AsciiTableHDU.
20126
+ *
20127
+ * - The legacy API serializes the former FITSParsed representation
20128
+ * and is retained for backward compatibility with jsfitsio 2.x
20129
+ * consumers.
20130
+ *
20131
+ * FITS headers are serialized according to the FITS 80-character
20132
+ * card format and padded to 2880-byte FITS logical blocks.
20133
+ * HDU payloads are likewise padded to 2880-byte boundaries.
20134
+ *
20135
+ * New code should use FITSFile together with createFITSFile() and
20136
+ * writeFITSFileModel().
20137
+ *
20138
+ * @see https://fits.gsfc.nasa.gov/
20139
+ */
20140
+
20141
+
20142
+ class FITSWriter {
20143
+ /**
20144
+ * Serializes the legacy FITSParsed representation.
20145
+ *
20146
+ * @deprecated Use createFITSFile() with the FITSFile/HDU model.
20147
+ * This method is retained for backward compatibility with jsfitsio 2.x.
20148
+ */
20149
+ static createFITS(fitsParsed) {
20150
+ const headerBytes = FITSHeaderWriter.serialize(fitsParsed.header, true);
20151
+ const dataBytes = this.createData(fitsParsed.data, fitsParsed.header);
20152
+ const fitsFile = new Uint8Array(headerBytes.length + dataBytes.length);
20153
+ fitsFile.set(headerBytes, 0);
20154
+ fitsFile.set(dataBytes, headerBytes.length);
20155
+ return fitsFile;
20156
+ }
20157
+ static createHDU(hdu, primary) {
20158
+ const headerBytes = FITSHeaderWriter.serialize(hdu.header, primary);
20159
+ const rawData = hdu.rawData ?? new Uint8Array(0);
20160
+ if (rawData.byteLength !== hdu.dataByteLength) {
20161
+ throw new Error(`HDU payload length mismatch: ` +
20162
+ `rawData contains ${rawData.byteLength} bytes, ` +
20163
+ `but dataByteLength=${hdu.dataByteLength}.`);
20164
+ }
20165
+ const dataBytes = FITSWriter.padData(rawData);
20166
+ const result = new Uint8Array(headerBytes.byteLength + dataBytes.byteLength);
20167
+ result.set(headerBytes, 0);
20168
+ result.set(dataBytes, headerBytes.byteLength);
20169
+ return result;
20170
+ }
20171
+ static padData(data) {
20172
+ const BLOCK = 2880;
20173
+ if (data.byteLength === 0) {
20174
+ return new Uint8Array(0);
20175
+ }
20176
+ const remainder = data.byteLength % BLOCK;
20177
+ if (remainder === 0) {
20178
+ return data.slice();
20179
+ }
20180
+ const padded = new Uint8Array(data.byteLength + (BLOCK - remainder));
20181
+ padded.set(data);
20182
+ return padded;
20183
+ }
20184
+ static createData(data, header) {
20185
+ // concat
20186
+ const totalLength = data.reduce((s, c) => s + c.length, 0);
20187
+ // OPTIONAL: verify size from BITPIX/NAXIS
20188
+ const bitpix = Math.abs(Number(header.findById("BITPIX")?.value ?? 0));
20189
+ const naxis = Number(header.findById("NAXIS")?.value ?? 0);
20190
+ let elems = 1;
20191
+ for (let k = 1; k <= naxis; k++) {
20192
+ elems *= Number(header.findById(`NAXIS${k}`)?.value ?? 0);
20193
+ }
20194
+ const bytesPerElem = bitpix / 8;
20195
+ const expectedUnpadded = naxis > 0 ? elems * bytesPerElem : 0;
20196
+ if (expectedUnpadded && expectedUnpadded !== totalLength) {
20197
+ throw new Error(`Data length ${totalLength} does not match header expectation ${expectedUnpadded} (BITPIX=${bitpix}, NAXIS=${naxis})`);
20198
+ }
20199
+ // build and pad
20200
+ let dataBytes = new Uint8Array(totalLength);
20201
+ let off = 0;
20202
+ for (const chunk of data) {
20203
+ dataBytes.set(chunk, off);
20204
+ off += chunk.length;
20205
+ }
20206
+ return FITSWriter.padData(dataBytes);
20207
+ }
20208
+ /**
20209
+ * Serializes a jsfitsio 3.x FITSFile, including all contained HDUs.
20210
+ */
20211
+ static createFITSFile(fitsFile) {
20212
+ if (fitsFile.length === 0) {
20213
+ throw new Error("Cannot write an empty FITSFile.");
20214
+ }
20215
+ if (fitsFile.primaryHDU === null) {
20216
+ throw new Error("FITSFile must start with a PrimaryHDU.");
20217
+ }
20218
+ const serializedHDUs = fitsFile.hdus.map((hdu, index) => FITSWriter.createHDU(hdu, index === 0));
20219
+ const totalLength = serializedHDUs.reduce((sum, hdu) => sum + hdu.byteLength, 0);
20220
+ const result = new Uint8Array(totalLength);
20221
+ let offset = 0;
20222
+ for (const hdu of serializedHDUs) {
20223
+ result.set(hdu, offset);
20224
+ offset += hdu.byteLength;
20225
+ }
20226
+ return result;
20227
+ }
20228
+ /**
20229
+ * Serializes a jsfitsio 3.x FITSFile and writes it to the local filesystem.
20230
+ */
20231
+ static writeFITSFileModel(fitsFile, filePath) {
20232
+ const data = FITSWriter.createFITSFile(fitsFile);
20233
+ external_fs_namespaceObject.writeFileSync(filePath, data);
20234
+ }
20235
+ /**
20236
+ * Writes the legacy FITSParsed representation to a local file.
20237
+ *
20238
+ * @deprecated Use writeFITSFileModel() with FITSFile instead.
20239
+ * This method is retained for backward compatibility with jsfitsio 2.x.
20240
+ */
20241
+ static writeFITSFile(fitsParsed, filePath) {
20242
+ const fitsFile = FITSWriter.createFITS(fitsParsed);
20243
+ external_fs_namespaceObject.writeFileSync(filePath, fitsFile);
20244
+ }
20245
+ }
20246
+ //# sourceMappingURL=FITSWriter.js.map
20247
+ ;// ./node_modules/jsfitsio/lib-esm/ParseHeader.js
20248
+ // import { FITSHeader } from "./model/FITSHeader.js";
20249
+
20250
+
20251
+ /**
20252
+ * Summary. (bla bla bla)
20253
+ *
20254
+ * Description. (bla bla bla)
20255
+ *
20256
+ * @link github https://github.com/fab77/FITSParser
20257
+ * @author Fabrizio Giordano <fabriziogiordano77@gmail.com>
20258
+ */
20259
+ class ParseHeader {
20260
+ static CARD_SIZE = 80;
20261
+ static BLOCK_SIZE = 2880;
20262
+ static getFITSItemStringValue(header, key) {
20263
+ const item = header.findById(key);
20264
+ if (!item) {
20265
+ return null;
20266
+ }
20267
+ return String(item.value).trim().replace(/^'/, "").replace(/'$/, "").trim();
20268
+ }
20269
+ static getFITSItemValue(header, key) {
20270
+ const item = header.findById(key);
20271
+ if (!item) {
20272
+ return null;
20273
+ }
20274
+ const value = Number(item.value);
20275
+ return Number.isNaN(value) ? null : value;
20276
+ }
20277
+ /**
20278
+ * Returns the complete FITS header size, including padding
20279
+ * up to the next 2880-byte boundary.
20280
+ */
20281
+ static getHeaderByteLength(rawData, startOffset = 0) {
20282
+ const decoder = new TextDecoder("ascii");
20283
+ for (let offset = startOffset; offset + ParseHeader.CARD_SIZE <= rawData.byteLength; offset += ParseHeader.CARD_SIZE) {
20284
+ const key = decoder.decode(rawData.subarray(offset, offset + 8)).trim();
20285
+ if (key === "END") {
20286
+ const consumed = offset + ParseHeader.CARD_SIZE - startOffset;
20287
+ return (Math.ceil(consumed / ParseHeader.BLOCK_SIZE) * ParseHeader.BLOCK_SIZE);
20288
+ }
20289
+ }
20290
+ throw new Error("Invalid FITS header: END card not found.");
20291
+ }
20292
+ static parse(rawData, startOffset = 0) {
20293
+ const decoder = new TextDecoder("ascii");
20294
+ const headerLength = ParseHeader.getHeaderByteLength(rawData, startOffset);
20295
+ const header = new FITSHeaderManager(false);
20296
+ for (let offset = startOffset; offset < startOffset + headerLength; offset += ParseHeader.CARD_SIZE) {
20297
+ const line = decoder.decode(rawData.subarray(offset, offset + ParseHeader.CARD_SIZE));
20298
+ const key = line.slice(0, 8).trim();
20299
+ if (key === "END") {
20300
+ break;
20301
+ }
20302
+ if (!key) {
20303
+ continue;
20304
+ }
20305
+ let value;
20306
+ let comment = "";
20307
+ const rawValue = line.slice(10).trim().split("/")[0].trim();
20308
+ if (Number.isNaN(Number(rawValue))) {
20309
+ value = rawValue;
20310
+ }
20311
+ else {
20312
+ value = Number(rawValue);
20313
+ }
20314
+ if (line.includes("/")) {
20315
+ comment = line.slice(10).trim().split("/")[1]?.trim() ?? "";
20316
+ }
20317
+ header.insert(new FITSHeaderItem(key, value, comment));
20318
+ }
20319
+ return header;
20320
+ }
20321
+ }
20322
+ //# sourceMappingURL=ParseHeader.js.map
20323
+ ;// ./node_modules/jsfitsio/lib-esm/FITSImageUtils.js
20324
+
20325
+
20326
+ class FITSImageUtils {
20327
+ static getShape(header) {
20328
+ const naxis = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS);
20329
+ if (naxis === null) {
20330
+ throw new Error("NAXIS not defined.");
20331
+ }
20332
+ if (!Number.isInteger(naxis) || naxis < 0) {
20333
+ throw new Error(`Invalid FITS NAXIS value: ${naxis}`);
20334
+ }
20335
+ const shape = [];
20336
+ for (let axis = 1; axis <= naxis; axis++) {
20337
+ const size = ParseHeader.getFITSItemValue(header, FITSHeaderManager.naxisKey(axis));
20338
+ if (size === null) {
20339
+ throw new Error(`NAXIS${axis} not defined.`);
20340
+ }
20341
+ shape.push(size);
20342
+ }
20343
+ return shape;
20344
+ }
20345
+ static getElementCount(shape) {
20346
+ if (shape.length === 0) {
20347
+ return 0;
20348
+ }
20349
+ return shape.reduce((total, dimension) => total * dimension, 1);
20350
+ }
20351
+ }
20352
+ //# sourceMappingURL=FITSImageUtils.js.map
20353
+ ;// ./node_modules/jsfitsio/lib-esm/ParsePayload.js
20354
+ // "use strict";
20355
+ /**
20356
+ * Summary. (bla bla bla)
20357
+ *
20358
+ * Description. (bla bla bla)
20359
+ *
20360
+ * @link github https://github.com/fab77/FITSParser
20361
+ * @author Fabrizio Giordano <fabriziogiordano77@gmail.com>
20362
+ */
20363
+
20364
+
20365
+
20366
+
20367
+ class ParsePayload {
20368
+ static SUPPORTED_BITPIX = new Set([8, 16, 32, 64, -32, -64]);
20369
+ static assertSupportedBITPIX(bitpix) {
20370
+ if (!ParsePayload.SUPPORTED_BITPIX.has(bitpix)) {
20371
+ throw new Error(`Unsupported FITS BITPIX value: ${bitpix}`);
20372
+ }
20373
+ }
20374
+ static extractPixelFromView(view, offset, bitpix) {
20375
+ switch (bitpix) {
20376
+ case 8:
20377
+ return view.getUint8(offset);
20378
+ case 16:
20379
+ return view.getInt16(offset, false);
20380
+ case 32:
20381
+ return view.getInt32(offset, false);
20382
+ case -32:
20383
+ return view.getFloat32(offset, false);
20384
+ case -64:
20385
+ return view.getFloat64(offset, false);
20386
+ case 64: {
20387
+ const value = view.getBigInt64(offset, false);
20388
+ const numeric = Number(value);
20389
+ if (!Number.isSafeInteger(numeric)) {
20390
+ throw new RangeError(`BITPIX=64 value ${value} cannot be represented ` +
20391
+ `exactly as a JavaScript number.`);
20392
+ }
20393
+ return numeric;
20394
+ }
20395
+ default:
20396
+ throw new Error(`Unsupported FITS BITPIX value: ${bitpix}`);
20397
+ }
20398
+ }
20399
+ static computePhysicalMinAndMax(header, payload) {
20400
+ const bitpix = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BITPIX);
20401
+ if (bitpix === null) {
20402
+ return null;
20403
+ }
20404
+ ParsePayload.assertSupportedBITPIX(bitpix);
20405
+ const shape = FITSImageUtils.getShape(header);
20406
+ /*
20407
+ * NAXIS=0 is a valid FITS HDU.
20408
+ */
20409
+ if (shape.length === 0 || payload.byteLength === 0) {
20410
+ return header;
20411
+ }
20412
+ const dataMinItem = header.findById(FITSHeaderManager.DATAMIN);
20413
+ const dataMaxItem = header.findById(FITSHeaderManager.DATAMAX);
20414
+ if (dataMinItem === null || dataMaxItem === null) {
20415
+ try {
20416
+ const [min, max] = ParsePayload.computePhysicalValues(payload, header);
20417
+ if (dataMinItem === null && min !== null) {
20418
+ header.insert(new FITSHeaderItem(FITSHeaderManager.DATAMIN, min, "computed by jsfitsio"));
20419
+ }
20420
+ if (dataMaxItem === null && max !== null) {
20421
+ header.insert(new FITSHeaderItem(FITSHeaderManager.DATAMAX, max, "computed by jsfitsio"));
20422
+ }
20423
+ }
20424
+ catch (error) {
20425
+ if (bitpix === 64 && error instanceof RangeError) {
20426
+ return header;
20427
+ }
20428
+ throw error;
20429
+ }
20430
+ }
20431
+ return header;
20432
+ }
20433
+ static createTypedArray(rawData, bitpix) {
20434
+ ParsePayload.assertSupportedBITPIX(bitpix);
20435
+ const bytesPerElement = Math.abs(bitpix) / 8;
20436
+ if (rawData.byteLength % bytesPerElement !== 0) {
20437
+ throw new Error(`Payload byte length ${rawData.byteLength} ` +
20438
+ `is not aligned with BITPIX=${bitpix}.`);
20439
+ }
20440
+ const count = rawData.byteLength / bytesPerElement;
20441
+ const view = new DataView(rawData.buffer, rawData.byteOffset, rawData.byteLength);
20442
+ switch (bitpix) {
20443
+ case 8: {
20444
+ /*
20445
+ * For 8-bit FITS, byte order is irrelevant.
20446
+ *
20447
+ * Use slice() so typedData has its own correctly
20448
+ * sized backing store.
20449
+ */
20450
+ return rawData.slice();
20451
+ }
20452
+ case 16: {
20453
+ const result = new Int16Array(count);
20454
+ for (let i = 0; i < count; i++) {
20455
+ result[i] = view.getInt16(i * 2, false);
20456
+ }
20457
+ return result;
20458
+ }
20459
+ case 32: {
20460
+ const result = new Int32Array(count);
20461
+ for (let i = 0; i < count; i++) {
20462
+ result[i] = view.getInt32(i * 4, false);
20463
+ }
20464
+ return result;
20465
+ }
20466
+ case 64: {
20467
+ const result = new BigInt64Array(count);
20468
+ for (let i = 0; i < count; i++) {
20469
+ result[i] = view.getBigInt64(i * 8, false);
20470
+ }
20471
+ return result;
20472
+ }
20473
+ case -32: {
20474
+ const result = new Float32Array(count);
20475
+ for (let i = 0; i < count; i++) {
20476
+ result[i] = view.getFloat32(i * 4, false);
20477
+ }
20478
+ return result;
20479
+ }
20480
+ case -64: {
20481
+ const result = new Float64Array(count);
20482
+ for (let i = 0; i < count; i++) {
20483
+ result[i] = view.getFloat64(i * 8, false);
20484
+ }
20485
+ return result;
20486
+ }
20487
+ default:
20488
+ throw new Error(`Unsupported FITS BITPIX value: ${bitpix}`);
20489
+ }
20490
+ }
20491
+ static computePhysicalValues(rawData, header) {
20492
+ const bitpix = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BITPIX);
20493
+ if (bitpix === null) {
20494
+ return [null, null];
20495
+ }
20496
+ ParsePayload.assertSupportedBITPIX(bitpix);
20497
+ const shape = FITSImageUtils.getShape(header);
20498
+ const pixelCount = FITSImageUtils.getElementCount(shape);
20499
+ if (pixelCount === 0) {
20500
+ return [null, null];
20501
+ }
20502
+ const blank = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BLANK);
20503
+ const bzero = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BZERO) ?? 0;
20504
+ const bscale = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BSCALE) ?? 1;
20505
+ const bytesPerElement = Math.abs(bitpix) / 8;
20506
+ const requiredBytes = pixelCount * bytesPerElement;
20507
+ if (rawData.byteLength < requiredBytes) {
20508
+ throw new Error(`FITS payload is too short: expected ${requiredBytes} bytes, ` +
20509
+ `received ${rawData.byteLength}.`);
20510
+ }
20511
+ const view = new DataView(rawData.buffer, rawData.byteOffset, rawData.byteLength);
20512
+ let min = null;
20513
+ let max = null;
20514
+ for (let i = 0; i < pixelCount; i++) {
20515
+ const rawValue = ParsePayload.extractPixelFromView(view, i * bytesPerElement, bitpix);
20516
+ // BLANK applies to integer FITS image data.
20517
+ if (bitpix > 0 && blank !== null && rawValue === blank) {
20518
+ continue;
20519
+ }
20520
+ const physicalValue = ParsePayload.pixel2physicalValue(rawValue, bscale, bzero);
20521
+ // Floating-point FITS images may contain NaN.
20522
+ if (Number.isNaN(physicalValue)) {
20523
+ continue;
20524
+ }
20525
+ if (min === null || physicalValue < min) {
20526
+ min = physicalValue;
20527
+ }
20528
+ if (max === null || physicalValue > max) {
20529
+ max = physicalValue;
20530
+ }
20531
+ }
20532
+ return [min, max];
20533
+ }
20534
+ static pixel2physicalValue(pxval, BSCALE, BZERO) {
20535
+ if (BZERO === null || BSCALE === null) {
20536
+ throw new Error("Either BZERO or BSCALE is null");
20537
+ }
20538
+ return BZERO + BSCALE * pxval;
20539
+ }
20540
+ static extractPixelValue(rawData, offset, bitpix) {
20541
+ ParsePayload.assertSupportedBITPIX(bitpix);
20542
+ const view = new DataView(rawData.buffer, rawData.byteOffset, rawData.byteLength);
20543
+ return ParsePayload.extractPixelFromView(view, offset, bitpix);
20544
+ }
20545
+ }
20546
+ //# sourceMappingURL=ParsePayload.js.map
20547
+ ;// ./node_modules/jsfitsio/lib-esm/model/FITSHDU.js
20548
+ class FITSHDU {
20549
+ header;
20550
+ rawData;
20551
+ dataOffset;
20552
+ dataByteLength;
20553
+ constructor(header, rawData, dataOffset, dataByteLength) {
20554
+ this.header = header;
20555
+ this.rawData = rawData;
20556
+ this.dataOffset = dataOffset;
20557
+ this.dataByteLength = dataByteLength;
20558
+ }
20559
+ }
20560
+ //# sourceMappingURL=FITSHDU.js.map
20561
+ ;// ./node_modules/jsfitsio/lib-esm/model/ImageHDU.js
20562
+
20563
+ class ImageHDU extends FITSHDU {
20564
+ bitpix;
20565
+ shape;
20566
+ typedData;
20567
+ type = "IMAGE";
20568
+ constructor(header, rawData, dataOffset, dataByteLength, bitpix, shape, typedData) {
20569
+ super(header, rawData, dataOffset, dataByteLength);
20570
+ this.bitpix = bitpix;
20571
+ this.shape = shape;
20572
+ this.typedData = typedData;
20573
+ }
20574
+ get naxis() {
20575
+ return this.shape.length;
20576
+ }
20577
+ get elementCount() {
20578
+ if (this.shape.length === 0) {
20579
+ return 0;
20580
+ }
20581
+ return this.shape.reduce((accumulator, dimension) => accumulator * dimension, 1);
20582
+ }
20583
+ }
20584
+ //# sourceMappingURL=ImageHDU.js.map
20585
+ ;// ./node_modules/jsfitsio/lib-esm/model/PrimaryHDU.js
20586
+
20587
+ class PrimaryHDU extends ImageHDU {
20588
+ type = "PRIMARY";
20589
+ constructor(header, rawData, dataOffset, dataByteLength, bitpix, shape, typedData) {
20590
+ super(header, rawData, dataOffset, dataByteLength, bitpix, shape, typedData);
20591
+ }
20592
+ }
20593
+ //# sourceMappingURL=PrimaryHDU.js.map
20594
+ ;// ./node_modules/jsfitsio/lib-esm/model/FITSFile.js
20595
+
20596
+ class FITSFile {
20597
+ _hdus;
20598
+ constructor(hdus = []) {
20599
+ this._hdus = [...hdus];
20600
+ }
20601
+ get hdus() {
20602
+ return this._hdus;
20603
+ }
20604
+ get length() {
20605
+ return this._hdus.length;
20606
+ }
20607
+ get primaryHDU() {
20608
+ const hdu = this._hdus[0];
20609
+ if (hdu instanceof PrimaryHDU) {
20610
+ return hdu;
20611
+ }
20612
+ return null;
20613
+ }
20614
+ getHDU(index) {
20615
+ return this._hdus[index] ?? null;
20616
+ }
20617
+ addHDU(hdu) {
20618
+ this._hdus.push(hdu);
20619
+ }
20620
+ }
20621
+ //# sourceMappingURL=FITSFile.js.map
20622
+ ;// ./node_modules/jsfitsio/lib-esm/model/BinaryTableHDU.js
20623
+
20624
+ class BinaryTableHDU extends FITSHDU {
20625
+ rowByteLength;
20626
+ rowCount;
20627
+ columns;
20628
+ type = "BINTABLE";
20629
+ constructor(header, rawData, dataOffset, dataByteLength, rowByteLength, rowCount, columns) {
20630
+ super(header, rawData, dataOffset, dataByteLength);
20631
+ this.rowByteLength = rowByteLength;
20632
+ this.rowCount = rowCount;
20633
+ this.columns = columns;
20634
+ }
20635
+ get columnCount() {
20636
+ return this.columns.length;
20637
+ }
20638
+ getRowView(rowIndex) {
20639
+ if (rowIndex < 0 || rowIndex >= this.rowCount) {
20640
+ throw new RangeError(`Invalid row index ${rowIndex}.`);
20641
+ }
20642
+ const offset = rowIndex * this.rowByteLength;
20643
+ return new DataView(this.rawData.buffer, this.rawData.byteOffset + offset, this.rowByteLength);
20644
+ }
20645
+ getRow(rowIndex) {
20646
+ return this.columns.map((_, columnIndex) => this.getCell(rowIndex, columnIndex));
20647
+ }
20648
+ getCell(rowIndex, column) {
20649
+ const columnDefinition = this.resolveColumn(column);
20650
+ const row = this.getRowView(rowIndex);
20651
+ const offset = columnDefinition.byteOffset;
20652
+ const repeat = columnDefinition.repeat;
20653
+ switch (columnDefinition.type) {
20654
+ case "CHAR": {
20655
+ const bytes = new Uint8Array(row.buffer, row.byteOffset + offset, columnDefinition.byteWidth);
20656
+ return new TextDecoder("ascii").decode(bytes).replace(/\s+$/, "");
20657
+ }
20658
+ case "LOGICAL": {
20659
+ const values = [];
20660
+ for (let i = 0; i < repeat; i++) {
20661
+ const value = String.fromCharCode(row.getUint8(offset + i));
20662
+ values.push(value === "T");
20663
+ }
20664
+ return repeat === 1 ? values[0] : values;
20665
+ }
20666
+ case "UINT8": {
20667
+ const values = [];
20668
+ for (let i = 0; i < repeat; i++) {
20669
+ const raw = row.getUint8(offset + i);
20670
+ values.push(this.applyNumericScaling(raw, columnDefinition.scale, columnDefinition.zero));
20671
+ }
20672
+ return repeat === 1 ? values[0] : values;
20673
+ }
20674
+ case "INT16":
20675
+ return this.readNumericColumn(row, offset, repeat, 2, (view, position) => view.getInt16(position, false), columnDefinition.scale, columnDefinition.zero, columnDefinition.nullValue);
20676
+ case "INT32":
20677
+ return this.readNumericColumn(row, offset, repeat, 4, (view, position) => view.getInt32(position, false), columnDefinition.scale, columnDefinition.zero, columnDefinition.nullValue);
20678
+ case "INT64": {
20679
+ const values = [];
20680
+ for (let i = 0; i < repeat; i++) {
20681
+ const raw = row.getBigInt64(offset + i * 8, false);
20682
+ /*
20683
+ * Preserve exact 64-bit integers.
20684
+ *
20685
+ * Do not silently convert bigint to number.
20686
+ */
20687
+ values.push(raw);
20688
+ }
20689
+ return repeat === 1 ? values[0] : values;
20690
+ }
20691
+ case "FLOAT32":
20692
+ return this.readNumericColumn(row, offset, repeat, 4, (view, position) => view.getFloat32(position, false), columnDefinition.scale, columnDefinition.zero, null);
20693
+ case "FLOAT64":
20694
+ return this.readNumericColumn(row, offset, repeat, 8, (view, position) => view.getFloat64(position, false), columnDefinition.scale, columnDefinition.zero, null);
20695
+ case "COMPLEX64": {
20696
+ const values = [];
20697
+ for (let i = 0; i < repeat; i++) {
20698
+ const position = offset + i * 8;
20699
+ values.push({
20700
+ real: row.getFloat32(position, false),
20701
+ imaginary: row.getFloat32(position + 4, false),
20702
+ });
20703
+ }
20704
+ return repeat === 1 ? values[0] : values;
20705
+ }
20706
+ case "COMPLEX128": {
20707
+ const values = [];
20708
+ for (let i = 0; i < repeat; i++) {
20709
+ const position = offset + i * 16;
20710
+ values.push({
20711
+ real: row.getFloat64(position, false),
20712
+ imaginary: row.getFloat64(position + 8, false),
20713
+ });
20714
+ }
20715
+ return repeat === 1 ? values[0] : values;
20716
+ }
20717
+ case "BIT":
20718
+ /*
20719
+ * I'd defer bit-array decoding for the moment.
20720
+ * The raw bytes remain available.
20721
+ */
20722
+ return new Uint8Array(row.buffer, row.byteOffset + offset, columnDefinition.byteWidth).slice();
20723
+ default:
20724
+ throw new Error(`Unsupported BINTABLE column type: ${columnDefinition.type}`);
20725
+ }
20726
+ }
20727
+ readNumericColumn(view, offset, repeat, bytesPerElement, reader, scale, zero, nullValue) {
20728
+ const values = [];
20729
+ for (let i = 0; i < repeat; i++) {
20730
+ const raw = reader(view, offset + i * bytesPerElement);
20731
+ if (nullValue !== null && raw === nullValue) {
20732
+ values.push(null);
20733
+ continue;
20734
+ }
20735
+ values.push(this.applyNumericScaling(raw, scale, zero));
20736
+ }
20737
+ if (repeat === 1) {
20738
+ return values[0];
20739
+ }
20740
+ /*
20741
+ * Because repeated integer fields may contain NULL,
20742
+ * we cannot represent every case as number[].
20743
+ *
20744
+ * For now return a generic value array.
20745
+ */
20746
+ return values;
20747
+ }
20748
+ applyNumericScaling(raw, scale, zero) {
20749
+ return zero + scale * raw;
20750
+ }
20751
+ resolveColumn(column) {
20752
+ if (typeof column === "number") {
20753
+ if (!Number.isInteger(column) ||
20754
+ column < 0 ||
20755
+ column >= this.columns.length) {
20756
+ throw new RangeError(`Invalid column index ${column}.`);
20757
+ }
20758
+ return this.columns[column];
20759
+ }
20760
+ const found = this.columns.find((candidate) => candidate.name === column);
20761
+ if (!found) {
20762
+ throw new Error(`BINTABLE column '${column}' not found.`);
20763
+ }
20764
+ return found;
20765
+ }
20766
+ }
20767
+ //# sourceMappingURL=BinaryTableHDU.js.map
20768
+ ;// ./node_modules/jsfitsio/lib-esm/FITSBinaryTableUtils.js
20769
+ class FITSBinaryTableUtils {
20770
+ static parseTFORM(format) {
20771
+ const normalized = format
20772
+ .trim()
20773
+ .replace(/^'/, "")
20774
+ .replace(/'$/, "")
20775
+ .trim()
20776
+ .toUpperCase();
20777
+ const match = normalized.match(/^(\d*)([LXBIJKAEDCM])$/);
20778
+ if (!match) {
20779
+ throw new Error(`Unsupported FITS TFORM value: ${format}`);
20780
+ }
20781
+ const repeat = match[1] ? Number(match[1]) : 1;
20782
+ const code = match[2];
20783
+ const bytesPerElement = FITSBinaryTableUtils.bytesPerType(code);
20784
+ return {
20785
+ repeat,
20786
+ code,
20787
+ byteWidth: code === "X" ? Math.ceil(repeat / 8) : repeat * bytesPerElement,
20788
+ };
20789
+ }
20790
+ static bytesPerType(code) {
20791
+ switch (code) {
20792
+ case "L":
20793
+ case "B":
20794
+ case "A":
20795
+ return 1;
20796
+ case "I":
20797
+ return 2;
20798
+ case "J":
20799
+ case "E":
20800
+ return 4;
20801
+ case "K":
20802
+ case "D":
20803
+ return 8;
20804
+ case "C":
20805
+ return 8;
20806
+ case "M":
20807
+ return 16;
20808
+ case "X":
20809
+ return 0;
20810
+ default:
20811
+ throw new Error(`Unsupported FITS binary table type: ${code}`);
20812
+ }
20813
+ }
20814
+ }
20815
+ //# sourceMappingURL=FITSBinaryTableUtils.js.map
20816
+ ;// ./node_modules/jsfitsio/lib-esm/model/AsciiTableHDU.js
20817
+
20818
+ class AsciiTableHDU extends FITSHDU {
20819
+ rowByteLength;
20820
+ rowCount;
20821
+ columns;
20822
+ type = "TABLE";
20823
+ constructor(header, rawData, dataOffset, dataByteLength, rowByteLength, rowCount, columns) {
20824
+ super(header, rawData, dataOffset, dataByteLength);
20825
+ this.rowByteLength = rowByteLength;
20826
+ this.rowCount = rowCount;
20827
+ this.columns = columns;
20828
+ }
20829
+ get columnCount() {
20830
+ return this.columns.length;
20831
+ }
20832
+ getRowView(rowIndex) {
20833
+ if (!Number.isInteger(rowIndex) ||
20834
+ rowIndex < 0 ||
20835
+ rowIndex >= this.rowCount) {
20836
+ throw new RangeError(`Invalid row index ${rowIndex}.`);
20837
+ }
20838
+ const start = rowIndex * this.rowByteLength;
20839
+ return this.rawData.subarray(start, start + this.rowByteLength);
20840
+ }
20841
+ getRowText(rowIndex) {
20842
+ return new TextDecoder("ascii").decode(this.getRowView(rowIndex));
20843
+ }
20844
+ resolveColumn(column) {
20845
+ if (typeof column === "number") {
20846
+ if (!Number.isInteger(column) ||
20847
+ column < 0 ||
20848
+ column >= this.columns.length) {
20849
+ throw new RangeError(`Invalid column index ${column}.`);
20850
+ }
20851
+ return this.columns[column];
20852
+ }
20853
+ const found = this.columns.find((candidate) => candidate.name === column);
20854
+ if (!found) {
20855
+ throw new Error(`ASCII TABLE column '${column}' not found.`);
20856
+ }
20857
+ return found;
20858
+ }
20859
+ getCell(rowIndex, column) {
20860
+ const definition = this.resolveColumn(column);
20861
+ const row = this.getRowView(rowIndex);
20862
+ const bytes = row.subarray(definition.byteOffset, definition.byteOffset + definition.width);
20863
+ const raw = new TextDecoder("ascii").decode(bytes);
20864
+ const trimmed = raw.trim();
20865
+ /*
20866
+ * Blank numeric fields are treated as null.
20867
+ */
20868
+ if (trimmed.length === 0) {
20869
+ return definition.type === "CHAR" ? "" : null;
20870
+ }
20871
+ switch (definition.type) {
20872
+ case "CHAR":
20873
+ return raw.replace(/\s+$/, "");
20874
+ case "INTEGER": {
20875
+ const value = Number.parseInt(trimmed, 10);
20876
+ if (Number.isNaN(value)) {
20877
+ return null;
20878
+ }
20879
+ return value;
20880
+ }
20881
+ case "FLOAT":
20882
+ case "EXPONENTIAL":
20883
+ case "DOUBLE": {
20884
+ /*
20885
+ * FITS ASCII tables may use D exponent notation.
20886
+ * JavaScript expects E.
20887
+ */
20888
+ const normalized = trimmed.replace(/[dD]/, "E");
20889
+ const value = Number.parseFloat(normalized);
20890
+ if (Number.isNaN(value)) {
20891
+ return null;
20892
+ }
20893
+ return value;
20894
+ }
20895
+ default:
20896
+ throw new Error(`Unsupported ASCII TABLE column type: ${definition.type}`);
20897
+ }
20898
+ }
20899
+ getRow(rowIndex) {
20900
+ return this.columns.map((_, columnIndex) => this.getCell(rowIndex, columnIndex));
20901
+ }
20902
+ }
20903
+ //# sourceMappingURL=AsciiTableHDU.js.map
20904
+ ;// ./node_modules/jsfitsio/lib-esm/FITSAsciiTableUtils.js
20905
+ class FITSAsciiTableUtils {
20906
+ static parseTFORM(format) {
20907
+ const normalized = format
20908
+ .trim()
20909
+ .replace(/^'/, "")
20910
+ .replace(/'$/, "")
20911
+ .trim()
20912
+ .toUpperCase();
20913
+ /*
20914
+ * FITS ASCII table formats:
20915
+ *
20916
+ * Aw
20917
+ * Iw
20918
+ * Fw.d
20919
+ * Ew.d
20920
+ * Dw.d
20921
+ */
20922
+ const match = normalized.match(/^([AIFED])(\d+)(?:\.(\d+))?$/);
20923
+ if (!match) {
20924
+ throw new Error(`Unsupported FITS ASCII table TFORM value: ${format}`);
20925
+ }
20926
+ const code = match[1];
20927
+ const width = Number(match[2]);
20928
+ const decimals = match[3] !== undefined
20929
+ ? Number(match[3])
20930
+ : null;
20931
+ if (!Number.isInteger(width) ||
20932
+ width <= 0) {
20933
+ throw new Error(`Invalid FITS ASCII table field width: ${width}`);
20934
+ }
20935
+ if (code === "A" ||
20936
+ code === "I") {
20937
+ if (decimals !== null) {
20938
+ throw new Error(`TFORM ${format} must not specify decimal places.`);
20939
+ }
20940
+ }
20941
+ else if (decimals === null) {
20942
+ throw new Error(`TFORM ${format} requires decimal places.`);
20943
+ }
20944
+ return {
20945
+ code,
20946
+ width,
20947
+ decimals,
20948
+ };
20949
+ }
20950
+ }
20951
+ //# sourceMappingURL=FITSAsciiTableUtils.js.map
20952
+ ;// ./node_modules/jsfitsio/lib-esm/FITSParser.js
20953
+
20954
+
20955
+
20956
+
20957
+
20958
+
20959
+
20960
+
20961
+
20962
+
20963
+
20964
+
20965
+ class FITSParser {
20966
+ /**
20967
+ * @deprecated Use loadFITSFile() instead.
20968
+ *
20969
+ * This legacy API supports only 2-dimensional image FITS files
20970
+ * and returns the former FITSParsed structure.
20971
+ */
20972
+ static async loadFITS(path, options = {}) {
20973
+ const fitsFile = await FITSParser.loadFITSFile(path, options);
20974
+ if (fitsFile === null) {
20975
+ return null;
20976
+ }
20977
+ const primary = fitsFile.primaryHDU;
20978
+ if (primary === null || primary.rawData === null) {
20979
+ return null;
20980
+ }
20981
+ const shape = FITSImageUtils.getShape(primary.header);
20982
+ if (shape.length !== 2) {
20983
+ throw new Error("Legacy loadFITS() supports only 2D FITS images. " +
20984
+ "Use loadFITSFile() for N-dimensional images.");
20985
+ }
20986
+ return {
20987
+ header: primary.header,
20988
+ data: FITSParser.createMatrix(primary.rawData, primary.header),
20989
+ };
20990
+ }
20991
+ static async loadFITSFile(path, options = {}) {
20992
+ const rawData = await FITSParser.getFile(path);
20993
+ if (rawData.byteLength === 0) {
20994
+ return null;
20995
+ }
20996
+ return FITSParser.processFITSFile(rawData, options);
20997
+ }
20998
+ static processFITSFile(rawData, options) {
20999
+ const fitsFile = new FITSFile();
21000
+ let offset = 0;
21001
+ let hduIndex = 0;
21002
+ while (offset < rawData.byteLength) {
21003
+ /*
21004
+ * Ignore trailing zero/space padding.
21005
+ */
21006
+ if (FITSParser.isPaddingOnly(rawData, offset)) {
21007
+ break;
21008
+ }
21009
+ const header = ParseHeader.parse(rawData, offset);
21010
+ const headerByteLength = ParseHeader.getHeaderByteLength(rawData, offset);
21011
+ const dataOffset = offset + headerByteLength;
21012
+ const hduType = FITSParser.getHDUType(header, hduIndex);
21013
+ switch (hduType) {
21014
+ case "PRIMARY":
21015
+ case "IMAGE": {
21016
+ const dataByteLength = FITSParser.getImagePayloadByteLength(header);
21017
+ if (dataOffset + dataByteLength > rawData.byteLength) {
21018
+ throw new Error(`Invalid FITS HDU ${hduIndex}: ` +
21019
+ `expected ${dataByteLength} payload bytes ` +
21020
+ `at offset ${dataOffset}, but only ` +
21021
+ `${rawData.byteLength - dataOffset} remain.`);
21022
+ }
21023
+ const rawPayload = rawData.subarray(dataOffset, dataOffset + dataByteLength);
21024
+ const hdu = FITSParser.createImageHDU(header, rawPayload, dataOffset, dataByteLength, hduIndex === 0, options);
21025
+ fitsFile.addHDU(hdu);
21026
+ const paddedPayloadLength = FITSParser.getPaddedByteLength(dataByteLength);
21027
+ offset = dataOffset + paddedPayloadLength;
21028
+ break;
21029
+ }
21030
+ case "BINTABLE": {
21031
+ const dataByteLength = FITSParser.getBinaryTablePayloadByteLength(header);
21032
+ if (dataOffset + dataByteLength > rawData.byteLength) {
21033
+ throw new Error(`Invalid BINTABLE HDU ${hduIndex}.`);
21034
+ }
21035
+ const rawPayload = rawData.subarray(dataOffset, dataOffset + dataByteLength);
21036
+ const hdu = FITSParser.createBinaryTableHDU(header, rawPayload, dataOffset, dataByteLength);
21037
+ fitsFile.addHDU(hdu);
21038
+ offset = dataOffset + FITSParser.getPaddedByteLength(dataByteLength);
21039
+ break;
21040
+ }
21041
+ case "TABLE": {
21042
+ const dataByteLength = FITSParser.getAsciiTablePayloadByteLength(header);
21043
+ if (dataOffset + dataByteLength > rawData.byteLength) {
21044
+ throw new Error(`Invalid ASCII TABLE HDU ${hduIndex}: ` +
21045
+ `expected ${dataByteLength} payload bytes ` +
21046
+ `at offset ${dataOffset}, but only ` +
21047
+ `${rawData.byteLength - dataOffset} remain.`);
21048
+ }
21049
+ const rawPayload = rawData.subarray(dataOffset, dataOffset + dataByteLength);
21050
+ const hdu = FITSParser.createAsciiTableHDU(header, rawPayload, dataOffset, dataByteLength);
21051
+ fitsFile.addHDU(hdu);
21052
+ offset = dataOffset + FITSParser.getPaddedByteLength(dataByteLength);
21053
+ break;
21054
+ }
21055
+ default:
21056
+ throw new Error(`Unsupported FITS HDU type at index ${hduIndex}.`);
21057
+ }
21058
+ hduIndex++;
21059
+ }
21060
+ return fitsFile;
21061
+ }
21062
+ static getPaddedByteLength(byteLength) {
21063
+ if (byteLength === 0) {
21064
+ return 0;
21065
+ }
21066
+ return (Math.ceil(byteLength / ParseHeader.BLOCK_SIZE) * ParseHeader.BLOCK_SIZE);
21067
+ }
21068
+ static isPaddingOnly(rawData, offset) {
21069
+ for (let i = offset; i < rawData.byteLength; i++) {
21070
+ const value = rawData[i];
21071
+ if (value !== 0x00 && value !== 0x20) {
21072
+ return false;
21073
+ }
21074
+ }
21075
+ return true;
21076
+ }
21077
+ static getHDUType(header, index) {
21078
+ if (index === 0) {
21079
+ return "PRIMARY";
21080
+ }
21081
+ const xtension = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.XTENSION);
21082
+ if (xtension === null) {
21083
+ return "UNKNOWN";
21084
+ }
21085
+ switch (xtension.toUpperCase()) {
21086
+ case "IMAGE":
21087
+ return "IMAGE";
21088
+ case "BINTABLE":
21089
+ return "BINTABLE";
21090
+ case "TABLE":
21091
+ return "TABLE";
21092
+ default:
21093
+ return "UNKNOWN";
21094
+ }
21095
+ }
21096
+ static createImageHDU(header, rawPayload, dataOffset, dataByteLength, primary, options) {
21097
+ const finalHeader = options.computeDataMinMax
21098
+ ? (ParsePayload.computePhysicalMinAndMax(header, rawPayload) ?? header)
21099
+ : header;
21100
+ const bitpix = ParseHeader.getFITSItemValue(finalHeader, FITSHeaderManager.BITPIX);
21101
+ if (bitpix === null) {
21102
+ throw new Error("BITPIX not defined.");
21103
+ }
21104
+ const shape = FITSImageUtils.getShape(finalHeader);
21105
+ const typedData = ParsePayload.createTypedArray(rawPayload, bitpix);
21106
+ if (primary) {
21107
+ return new PrimaryHDU(finalHeader, rawPayload, dataOffset, dataByteLength, bitpix, shape, typedData);
21108
+ }
21109
+ return new ImageHDU(finalHeader, rawPayload, dataOffset, dataByteLength, bitpix, shape, typedData);
21110
+ }
21111
+ static getImagePayloadByteLength(header) {
21112
+ const bitpix = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BITPIX);
21113
+ if (bitpix === null) {
21114
+ throw new Error("BITPIX not defined.");
21115
+ }
21116
+ ParsePayload.assertSupportedBITPIX(bitpix);
21117
+ const shape = FITSImageUtils.getShape(header);
21118
+ if (shape.length === 0) {
21119
+ return 0;
21120
+ }
21121
+ const elementCount = shape.reduce((total, dimension) => total * dimension, 1);
21122
+ const bytesPerElement = Math.abs(bitpix) / 8;
21123
+ return elementCount * bytesPerElement;
21124
+ }
21125
+ static getBinaryTablePayloadByteLength(header) {
21126
+ const rowByteLength = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS1);
21127
+ const rowCount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS2);
21128
+ const pcount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.PCOUNT) ?? 0;
21129
+ if (rowByteLength === null || rowCount === null) {
21130
+ throw new Error("BINTABLE requires NAXIS1 and NAXIS2.");
21131
+ }
21132
+ return rowByteLength * rowCount + pcount;
21133
+ }
21134
+ static getBinaryTableColumns(header) {
21135
+ const fieldCount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.TFIELDS);
21136
+ if (fieldCount === null) {
21137
+ throw new Error("BINTABLE requires TFIELDS.");
21138
+ }
21139
+ const columns = [];
21140
+ let byteOffset = 0;
21141
+ for (let index = 1; index <= fieldCount; index++) {
21142
+ const tform = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.tableFieldKey("TFORM", index));
21143
+ if (tform === null) {
21144
+ throw new Error(`Missing TFORM${index}.`);
21145
+ }
21146
+ const parsed = FITSBinaryTableUtils.parseTFORM(tform);
21147
+ const name = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.tableFieldKey("TTYPE", index));
21148
+ const unit = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.tableFieldKey("TUNIT", index));
21149
+ columns.push({
21150
+ index,
21151
+ name,
21152
+ format: tform,
21153
+ type: FITSParser.mapBinaryType(parsed.code),
21154
+ repeat: parsed.repeat,
21155
+ byteOffset,
21156
+ byteWidth: parsed.byteWidth,
21157
+ unit,
21158
+ scale: ParseHeader.getFITSItemValue(header, FITSHeaderManager.tableFieldKey("TSCAL", index)) ?? 1,
21159
+ zero: ParseHeader.getFITSItemValue(header, FITSHeaderManager.tableFieldKey("TZERO", index)) ?? 0,
21160
+ nullValue: ParseHeader.getFITSItemValue(header, FITSHeaderManager.tableFieldKey("TNULL", index)),
21161
+ });
21162
+ byteOffset += parsed.byteWidth;
21163
+ }
21164
+ return columns;
21165
+ }
21166
+ static mapBinaryType(code) {
21167
+ switch (code.toUpperCase()) {
21168
+ case "L":
21169
+ return "LOGICAL";
21170
+ case "X":
21171
+ return "BIT";
21172
+ case "B":
21173
+ return "UINT8";
21174
+ case "I":
21175
+ return "INT16";
21176
+ case "J":
21177
+ return "INT32";
21178
+ case "K":
21179
+ return "INT64";
21180
+ case "A":
21181
+ return "CHAR";
21182
+ case "E":
21183
+ return "FLOAT32";
21184
+ case "D":
21185
+ return "FLOAT64";
21186
+ case "C":
21187
+ return "COMPLEX64";
21188
+ case "M":
21189
+ return "COMPLEX128";
21190
+ default:
21191
+ return "UNKNOWN";
21192
+ }
21193
+ }
21194
+ static createBinaryTableHDU(header, rawPayload, dataOffset, dataByteLength) {
21195
+ const rowByteLength = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS1);
21196
+ const rowCount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS2);
21197
+ if (rowByteLength === null || rowCount === null) {
21198
+ throw new Error("Invalid BINTABLE header.");
21199
+ }
21200
+ const columns = FITSParser.getBinaryTableColumns(header);
21201
+ const columnsByteWidth = columns.reduce((sum, column) => sum + column.byteWidth, 0);
21202
+ if (columnsByteWidth !== rowByteLength) {
21203
+ throw new Error(`BINTABLE columns occupy ${columnsByteWidth} bytes per row, ` +
21204
+ `but NAXIS1=${rowByteLength}.`);
21205
+ }
21206
+ return new BinaryTableHDU(header, rawPayload, dataOffset, dataByteLength, rowByteLength, rowCount, columns);
21207
+ }
21208
+ static getAsciiTablePayloadByteLength(header) {
21209
+ const rowByteLength = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS1);
21210
+ const rowCount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS2);
21211
+ if (rowByteLength === null || rowCount === null) {
21212
+ throw new Error("ASCII TABLE requires NAXIS1 and NAXIS2.");
21213
+ }
21214
+ if (!Number.isInteger(rowByteLength) || rowByteLength < 0) {
21215
+ throw new Error(`Invalid ASCII TABLE NAXIS1=${rowByteLength}.`);
21216
+ }
21217
+ if (!Number.isInteger(rowCount) || rowCount < 0) {
21218
+ throw new Error(`Invalid ASCII TABLE NAXIS2=${rowCount}.`);
21219
+ }
21220
+ const pcount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.PCOUNT) ?? 0;
21221
+ if (pcount !== 0) {
21222
+ throw new Error(`ASCII TABLE requires PCOUNT=0, received ${pcount}.`);
21223
+ }
21224
+ return rowByteLength * rowCount;
21225
+ }
21226
+ static mapAsciiType(code) {
21227
+ switch (code.toUpperCase()) {
21228
+ case "A":
21229
+ return "CHAR";
21230
+ case "I":
21231
+ return "INTEGER";
21232
+ case "F":
21233
+ return "FLOAT";
21234
+ case "E":
21235
+ return "EXPONENTIAL";
21236
+ case "D":
21237
+ return "DOUBLE";
21238
+ default:
21239
+ return "UNKNOWN";
21240
+ }
21241
+ }
21242
+ static getAsciiTableColumns(header) {
21243
+ const fieldCount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.TFIELDS);
21244
+ if (fieldCount === null) {
21245
+ throw new Error("ASCII TABLE requires TFIELDS.");
21246
+ }
21247
+ if (!Number.isInteger(fieldCount) || fieldCount < 0) {
21248
+ throw new Error(`Invalid ASCII TABLE TFIELDS=${fieldCount}.`);
21249
+ }
21250
+ const columns = [];
21251
+ for (let index = 1; index <= fieldCount; index++) {
21252
+ const tform = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.tableFieldKey("TFORM", index));
21253
+ if (tform === null) {
21254
+ throw new Error(`Missing TFORM${index}.`);
21255
+ }
21256
+ const tbcol = ParseHeader.getFITSItemValue(header, FITSHeaderManager.tableFieldKey("TBCOL", index));
21257
+ if (tbcol === null) {
21258
+ throw new Error(`Missing TBCOL${index}.`);
21259
+ }
21260
+ if (!Number.isInteger(tbcol) || tbcol < 1) {
21261
+ throw new Error(`Invalid TBCOL${index}=${tbcol}.`);
21262
+ }
21263
+ const parsed = FITSAsciiTableUtils.parseTFORM(tform);
21264
+ const name = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.tableFieldKey("TTYPE", index));
21265
+ const unit = ParseHeader.getFITSItemStringValue(header, FITSHeaderManager.tableFieldKey("TUNIT", index));
21266
+ columns.push({
21267
+ index,
21268
+ name,
21269
+ format: tform,
21270
+ type: FITSParser.mapAsciiType(parsed.code),
21271
+ startColumn: tbcol,
21272
+ /*
21273
+ * FITS TBCOL is 1-based.
21274
+ * JavaScript offsets are 0-based.
21275
+ */
21276
+ byteOffset: tbcol - 1,
21277
+ width: parsed.width,
21278
+ decimals: parsed.decimals,
21279
+ unit,
21280
+ });
21281
+ }
21282
+ return columns;
21283
+ }
21284
+ static validateAsciiTableColumns(columns, rowByteLength) {
21285
+ for (const column of columns) {
21286
+ const endOffset = column.byteOffset + column.width;
21287
+ if (endOffset > rowByteLength) {
21288
+ throw new Error(`ASCII TABLE column ${column.index} ` +
21289
+ `extends to byte ${endOffset}, ` +
21290
+ `but NAXIS1=${rowByteLength}.`);
21291
+ }
21292
+ }
21293
+ }
21294
+ static createAsciiTableHDU(header, rawPayload, dataOffset, dataByteLength) {
21295
+ const rowByteLength = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS1);
21296
+ const rowCount = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS2);
21297
+ if (rowByteLength === null || rowCount === null) {
21298
+ throw new Error("Invalid ASCII TABLE header.");
21299
+ }
21300
+ const columns = FITSParser.getAsciiTableColumns(header);
21301
+ FITSParser.validateAsciiTableColumns(columns, rowByteLength);
21302
+ return new AsciiTableHDU(header, rawPayload, dataOffset, dataByteLength, rowByteLength, rowCount, columns);
21303
+ }
21304
+ static createMatrix(payload, header) {
21305
+ const NAXIS1 = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS1);
21306
+ if (NAXIS1 === null) {
21307
+ throw new Error("NAXIS1 not defined.");
21308
+ }
21309
+ const NAXIS2 = ParseHeader.getFITSItemValue(header, FITSHeaderManager.NAXIS2);
21310
+ if (NAXIS2 === null) {
21311
+ throw new Error("NAXIS2 not defined.");
21312
+ }
21313
+ const BITPIX = ParseHeader.getFITSItemValue(header, FITSHeaderManager.BITPIX);
21314
+ if (BITPIX === null) {
21315
+ throw new Error("BITPIX not defined.");
21316
+ }
21317
+ const bytesXelem = Math.abs(BITPIX / 8);
21318
+ // if (payload.length !== NAXIS1 * NAXIS2 * bytesXelem) {
21319
+ // throw new Error("Payload size does not match the expected matrix dimensions.");
21320
+ // }
21321
+ // const matrix: Array<Uint8Array> = [];
21322
+ const matrix = [];
21323
+ for (let i = 0; i < NAXIS2; i++) {
21324
+ matrix.push(payload.slice(i * NAXIS1 * bytesXelem, (i + 1) * NAXIS1 * bytesXelem));
21325
+ }
21326
+ return matrix;
21327
+ }
21328
+ /**
21329
+ * @deprecated Legacy FITSParsed writer API.
21330
+ */
21331
+ static saveFITSLocally(fitsParsed, path) {
21332
+ return FITSWriter.writeFITSFile(fitsParsed, path);
21333
+ }
21334
+ static async getFile(uri) {
21335
+ if (!uri.substring(0, 5).toLowerCase().includes("http")) {
21336
+ const p = await __webpack_require__.e(/* import() */ 64).then(__webpack_require__.bind(__webpack_require__, 7064));
21337
+ const rawData = await p.getLocalFile(uri);
21338
+ if (rawData?.length) {
21339
+ const uint8 = new Uint8Array(rawData);
21340
+ return uint8;
21341
+ }
21342
+ return new Uint8Array(0);
21343
+ }
21344
+ else {
21345
+ const p = await __webpack_require__.e(/* import() */ 911).then(__webpack_require__.bind(__webpack_require__, 1911));
21346
+ const rawData = await p.getFile(uri);
21347
+ if (rawData?.byteLength) {
21348
+ const uint8 = new Uint8Array(rawData);
21349
+ return uint8;
21350
+ }
21351
+ return new Uint8Array(0);
21352
+ }
21353
+ }
21354
+ }
21355
+ // const url = "http://skies.esac.esa.int/Herschel/normalized/PACS_hips160//Norder8/Dir40000/Npix47180.fits"
21356
+ // FITSParser.loadFITS(url).then((fits) => {
21357
+ // if (fits == null) {
21358
+ // return null
21359
+ // }
21360
+ // const path = "./fitsTest1.fits"
21361
+ // console.log(fits.header)
21362
+ // FITSParser.saveFITSLocally(fits, path)
21363
+ // console.log("finished")
21364
+ // })
21365
+ // // const file = "/Users/fabriziogiordano/Desktop/PhD/code/new/FITSParser/tests/inputs/empty.fits"
21366
+ // const file = "/Users/fabriziogiordano/Desktop/PhD/code/new/FITSParser/tests/inputs/Npix43348.fits"
21367
+ // FITSParser.loadFITS(file).then((fits) => {
21368
+ // if (fits == null) {
21369
+ // return null
21370
+ // }
21371
+ // const path = "./fitsTest2.fits"
21372
+ // console.log(fits.header)
21373
+ // FITSParser.saveFITSLocally(fits, path)
21374
+ // console.log("finished")
21375
+ // })
21376
+ //# sourceMappingURL=FITSParser.js.map
21377
+ ;// ./node_modules/jsfitsio/lib-esm/index.js
21378
+
21379
+
21380
+
21381
+
21382
+
21383
+
21384
+
21385
+
21386
+
21387
+
21388
+
21389
+
21390
+ //# sourceMappingURL=index.js.map
21391
+
21392
+ /***/ }
21393
+
21394
+ /******/ });
21395
+ /************************************************************************/
21396
+ /******/ // The module cache
21397
+ /******/ const __webpack_module_cache__ = {};
21398
+ /******/
21399
+ /******/ // The require function
21400
+ /******/ function __webpack_require__(moduleId) {
21401
+ /******/ // Check if module is in cache
21402
+ /******/ const cachedModule = __webpack_module_cache__[moduleId];
21403
+ /******/ if (cachedModule !== undefined) {
21404
+ /******/ return cachedModule.exports;
21405
+ /******/ }
21406
+ /******/ // Create a new module (and put it into the cache)
21407
+ /******/ const module = __webpack_module_cache__[moduleId] = {
21408
+ /******/ // no module.id needed
21409
+ /******/ // no module.loaded needed
21410
+ /******/ exports: {}
21411
+ /******/ };
21412
+ /******/
21413
+ /******/ // Execute the module function
21414
+ /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21415
+ /******/
21416
+ /******/ // Return the exports of the module
21417
+ /******/ return module.exports;
21418
+ /******/ }
21419
+ /******/
21420
+ /******/ // expose the modules object (__webpack_modules__)
21421
+ /******/ __webpack_require__.m = __webpack_modules__;
21422
+ /******/
21423
+ /************************************************************************/
21424
+ /******/ /* webpack/runtime/define property getters */
21425
+ /******/ (() => {
21426
+ /******/ // define getter/value functions for harmony exports
21427
+ /******/ __webpack_require__.d = (exports, definition) => {
21428
+ /******/ if(Array.isArray(definition)) {
21429
+ /******/ var i = 0;
21430
+ /******/ while(i < definition.length) {
21431
+ /******/ var key = definition[i++];
21432
+ /******/ var binding = definition[i++];
21433
+ /******/ if(!__webpack_require__.o(exports, key)) {
21434
+ /******/ if(binding === 0) {
21435
+ /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
21436
+ /******/ } else {
21437
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
21438
+ /******/ }
21439
+ /******/ } else if(binding === 0) { i++; }
21440
+ /******/ }
21441
+ /******/ } else {
21442
+ /******/ for(var key in definition) {
21443
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
21444
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
21445
+ /******/ }
21446
+ /******/ }
21447
+ /******/ }
21448
+ /******/ };
21449
+ /******/ })();
21450
+ /******/
21451
+ /******/ /* webpack/runtime/ensure chunk */
21452
+ /******/ (() => {
21453
+ /******/ __webpack_require__.f = {};
21454
+ /******/ // This file contains only the entry chunk.
21455
+ /******/ // The chunk loading function for additional chunks
21456
+ /******/ __webpack_require__.e = (chunkId) => {
21457
+ /******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
21458
+ /******/ __webpack_require__.f[key](chunkId, promises);
21459
+ /******/ return promises;
21460
+ /******/ }, []));
21461
+ /******/ };
21462
+ /******/ })();
21463
+ /******/
21464
+ /******/ /* webpack/runtime/get javascript chunk filename */
21465
+ /******/ (() => {
21466
+ /******/ // This function allow to reference async chunks
21467
+ /******/ __webpack_require__.u = (chunkId) => {
21468
+ /******/ // return url for filenames based on template
21469
+ /******/ return "" + chunkId + ".astroviewer.cjs";
21470
+ /******/ };
21471
+ /******/ })();
21472
+ /******/
21473
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
21474
+ /******/ (() => {
21475
+ /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
21476
+ /******/ })();
21477
+ /******/
21478
+ /******/ /* webpack/runtime/make namespace object */
21479
+ /******/ (() => {
21480
+ /******/ // define __esModule on exports
21481
+ /******/ __webpack_require__.r = (exports) => {
21482
+ /******/ if(Symbol.toStringTag) {
21483
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
21484
+ /******/ }
21485
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
21486
+ /******/ };
21487
+ /******/ })();
21488
+ /******/
21489
+ /******/ /* webpack/runtime/require chunk loading */
21490
+ /******/ (() => {
21491
+ /******/ // no baseURI
21492
+ /******/
21493
+ /******/ // object to store loaded chunks
21494
+ /******/ // "1" means "loaded", otherwise not loaded yet
21495
+ /******/ const installedChunks = {
21496
+ /******/ 792: 1
21497
+ /******/ };
21498
+ /******/
21499
+ /******/ // no on chunks loaded
21500
+ /******/
21501
+ /******/ const installChunk = (chunk) => {
21502
+ /******/ const moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;
21503
+ /******/ for(var moduleId in moreModules) {
21504
+ /******/ if(__webpack_require__.o(moreModules, moduleId)) {
21505
+ /******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
21506
+ /******/ }
21507
+ /******/ }
21508
+ /******/ if(runtime) runtime(__webpack_require__);
21509
+ /******/ for(var i = 0; i < chunkIds.length; i++)
21510
+ /******/ installedChunks[chunkIds[i]] = 1;
21511
+ /******/
21512
+ /******/ };
21513
+ /******/
21514
+ /******/ // require() chunk loading for javascript
21515
+ /******/ __webpack_require__.f.require = (chunkId, promises) => {
21516
+ /******/ // "1" is the signal for "already loaded"
21517
+ /******/ if(!installedChunks[chunkId]) {
21518
+ /******/ if(true) { // all chunks have JS
21519
+ /******/ const installedChunk = require("./" + __webpack_require__.u(chunkId));
21520
+ /******/ if (!installedChunks[chunkId]) {
21521
+ /******/ installChunk(installedChunk);
21522
+ /******/ }
21523
+ /******/ } else installedChunks[chunkId] = 1;
21524
+ /******/ }
19337
21525
  /******/ };
21526
+ /******/
21527
+ /******/ // no external install chunk
21528
+ /******/
21529
+ /******/ // no HMR
21530
+ /******/
21531
+ /******/ // no HMR manifest
19338
21532
  /******/ })();
19339
21533
  /******/
19340
21534
  /************************************************************************/