astro-viewer 3.2.1 → 3.3.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.
@@ -2439,6 +2439,7 @@ const XYZTileRequestScheduler_js_1 = __webpack_require__(5409);
2439
2439
  const XYZMapDescriptor_js_1 = __webpack_require__(8868);
2440
2440
  const TerraPointSetGL_js_1 = __webpack_require__(5781);
2441
2441
  const TerraFootprintSetGL_js_1 = __webpack_require__(9022);
2442
+ const MeshHiPSDescriptor_js_1 = __webpack_require__(847);
2442
2443
  // & {
2443
2444
  // viewportWidth: number
2444
2445
  // viewportHeight: number
@@ -2554,6 +2555,9 @@ class AstroViewer {
2554
2555
  activateWMTS(config) {
2555
2556
  this.astroSphere.activateWMTS(config);
2556
2557
  }
2558
+ activateMeshHiPS(config) {
2559
+ this.astroSphere.activateMeshHiPS(new MeshHiPSDescriptor_js_1.MeshHiPSDescriptor(config));
2560
+ }
2557
2561
  setXYZMaxConcurrentRequests(value) {
2558
2562
  XYZTileRequestScheduler_js_1.xyzTileRequestScheduler.setMaxConcurrent(value);
2559
2563
  }
@@ -2566,6 +2570,9 @@ class AstroViewer {
2566
2570
  getHiPSDebugStats() {
2567
2571
  return this.astroSphere.getHiPSDebugStats();
2568
2572
  }
2573
+ getMeshHiPSDebugStats() {
2574
+ return this.astroSphere.getMeshHiPSDebugStats();
2575
+ }
2569
2576
  async loadHiPS(baseUrl) {
2570
2577
  const hipsUrl = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
2571
2578
  const resp = await fetch(hipsUrl + 'properties');
@@ -2577,6 +2584,26 @@ class AstroViewer {
2577
2584
  return desc.surveyName;
2578
2585
  // this.activateHiPS(desc);
2579
2586
  }
2587
+ async loadMeshHiPS(baseUrl, config = {}) {
2588
+ const meshHiPSUrl = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
2589
+ let propsText = '';
2590
+ const resp = await fetch(meshHiPSUrl + 'properties');
2591
+ if (resp.ok) {
2592
+ propsText = await resp.text();
2593
+ }
2594
+ else {
2595
+ const jsonResp = await fetch(meshHiPSUrl + 'properties.json');
2596
+ if (!jsonResp.ok)
2597
+ throw new Error(`HTTP ${jsonResp.status} fetching MeshHiPS properties`);
2598
+ const json = await jsonResp.json();
2599
+ propsText = Object.entries(json)
2600
+ .map(([key, value]) => `${key}=${String(value)}`)
2601
+ .join('\n');
2602
+ }
2603
+ const desc = new MeshHiPSDescriptor_js_1.MeshHiPSDescriptor({ ...config, baseUrl: meshHiPSUrl }, propsText);
2604
+ this.astroSphere.activateMeshHiPS(desc);
2605
+ return desc.name;
2606
+ }
2580
2607
  // changeColorMap(hips: HiPS, colorMapName: ColorMapName) {
2581
2608
  changeColorMap(colorMapName) {
2582
2609
  const colorMap = ColorMaps_js_1.default[colorMapName];
@@ -2862,6 +2889,149 @@ class AstroViewer {
2862
2889
  exports.AstroViewer = AstroViewer;
2863
2890
 
2864
2891
 
2892
+ /***/ }),
2893
+
2894
+ /***/ 847:
2895
+ /***/ ((__unused_webpack_module, exports) => {
2896
+
2897
+
2898
+ /*
2899
+ * AstroViewer
2900
+ * Copyright (C) Fabrizio Giordano
2901
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
2902
+ */
2903
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2904
+ exports.MeshHiPSDescriptor = void 0;
2905
+ class MeshHiPSDescriptor {
2906
+ _name = 'MeshHiPS';
2907
+ _baseUrl;
2908
+ _minOrder = 0;
2909
+ _maxOrder = 0;
2910
+ _selectedOrder;
2911
+ _fixedOrder = false;
2912
+ _maxCachedTiles = 384;
2913
+ // default neutral color (contrasts with page background)
2914
+ _color = [0.32, 0.34, 0.36, 1.0];
2915
+ _wireframe = false;
2916
+ _propertiesRawText = '';
2917
+ _propertiesMap = new Map();
2918
+ _meshRadius = null;
2919
+ constructor(config, propertiesText = '') {
2920
+ this._baseUrl = this.normalizeBaseUrl(config.baseUrl);
2921
+ this._propertiesRawText = propertiesText;
2922
+ this.parseProperties(propertiesText);
2923
+ this._name = config.name ?? this._propertiesMap.get('obs_collection') ?? this._propertiesMap.get('label') ?? this._name;
2924
+ this._minOrder = config.minOrder ?? this.readNumber('hips_order_min', this._minOrder);
2925
+ this._maxOrder = config.maxOrder ?? this.readNumber('hips_order', this.readNumber('hips_order_max', this._maxOrder));
2926
+ this._fixedOrder = config.order !== undefined;
2927
+ this._selectedOrder = config.order ?? this._minOrder;
2928
+ this._maxCachedTiles = config.maxCachedTiles ?? this._maxCachedTiles;
2929
+ // color: prefer explicit config, then properties.mesh_color, then default
2930
+ if (config.color) {
2931
+ this._color = config.color;
2932
+ }
2933
+ else if (this._propertiesMap.has('mesh_color')) {
2934
+ const raw = this._propertiesMap.get('mesh_color') || '';
2935
+ const parts = raw.split(/[,\s]+/).map((v) => Number(v)).filter(Number.isFinite);
2936
+ if (parts.length >= 3) {
2937
+ let [r, g, b, a] = parts;
2938
+ if (r > 1 || g > 1 || b > 1) {
2939
+ // assume 0-255 range
2940
+ r = r / 255;
2941
+ g = g / 255;
2942
+ b = b / 255;
2943
+ }
2944
+ if (!Number.isFinite(a))
2945
+ a = 1;
2946
+ this._color = [r, g, b, a];
2947
+ }
2948
+ }
2949
+ else {
2950
+ this._color = this._color;
2951
+ }
2952
+ this._wireframe = config.wireframe ?? this._wireframe;
2953
+ this._selectedOrder = this.clampOrder(this._selectedOrder);
2954
+ // mesh radius: prefer explicit value from config, otherwise read mandatory property
2955
+ if (Number.isFinite(config.meshRadius)) {
2956
+ this._meshRadius = config.meshRadius;
2957
+ }
2958
+ else {
2959
+ const radiusFromProps = this.readNumber('mesh_radius', NaN);
2960
+ if (!Number.isFinite(radiusFromProps)) {
2961
+ throw new Error('Missing mandatory property "mesh_radius" in MeshHiPS properties');
2962
+ }
2963
+ this._meshRadius = radiusFromProps;
2964
+ }
2965
+ }
2966
+ get name() {
2967
+ return this._name;
2968
+ }
2969
+ get baseUrl() {
2970
+ return this._baseUrl;
2971
+ }
2972
+ get minOrder() {
2973
+ return this._minOrder;
2974
+ }
2975
+ get maxOrder() {
2976
+ return this._maxOrder;
2977
+ }
2978
+ get selectedOrder() {
2979
+ return this._selectedOrder;
2980
+ }
2981
+ get fixedOrder() {
2982
+ return this._fixedOrder;
2983
+ }
2984
+ get maxCachedTiles() {
2985
+ return this._maxCachedTiles;
2986
+ }
2987
+ get color() {
2988
+ return this._color;
2989
+ }
2990
+ get wireframe() {
2991
+ return this._wireframe;
2992
+ }
2993
+ get propertiesRawText() {
2994
+ return this._propertiesRawText;
2995
+ }
2996
+ get properties() {
2997
+ return new Map(this._propertiesMap);
2998
+ }
2999
+ get meshRadius() {
3000
+ return this._meshRadius;
3001
+ }
3002
+ getProperty(key) {
3003
+ return this._propertiesMap.get(key);
3004
+ }
3005
+ getTileUrl(order, ipix) {
3006
+ const dir = Math.floor(ipix / 10_000) * 10_000;
3007
+ return `${this._baseUrl}Norder${order}/Dir${dir}/Npix${ipix}.obj`;
3008
+ }
3009
+ parseProperties(propertiesText) {
3010
+ const lines = propertiesText.split(/\r\n|\n/);
3011
+ for (const raw of lines) {
3012
+ const line = raw.trim();
3013
+ if (!line || line.startsWith('#'))
3014
+ continue;
3015
+ const idx = line.indexOf('=');
3016
+ if (idx < 0)
3017
+ continue;
3018
+ this._propertiesMap.set(line.slice(0, idx).trim(), line.slice(idx + 1).trim());
3019
+ }
3020
+ }
3021
+ readNumber(key, fallback) {
3022
+ const parsed = Number(this._propertiesMap.get(key));
3023
+ return Number.isFinite(parsed) ? parsed : fallback;
3024
+ }
3025
+ clampOrder(order) {
3026
+ return Math.max(this._minOrder, Math.min(this._maxOrder, order));
3027
+ }
3028
+ normalizeBaseUrl(baseUrl) {
3029
+ return baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
3030
+ }
3031
+ }
3032
+ exports.MeshHiPSDescriptor = MeshHiPSDescriptor;
3033
+
3034
+
2865
3035
  /***/ }),
2866
3036
 
2867
3037
  /***/ 1072:
@@ -4436,7 +4606,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4436
4606
  return (mod && mod.__esModule) ? mod : { "default": mod };
4437
4607
  };
4438
4608
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4439
- exports.Footprint = exports.Source = exports.WMTSAdapter = exports.XYZMap = exports.HiPS = exports.createColorMapFromSamples = exports.COLOR_MAP_SAMPLE_COUNT = exports.ColorMaps = exports.GeoJSONParser = exports.CoordsType = exports.FoVUtils = exports.CartesianOpts = exports.PointInitOpts = exports.AstroOpts = exports.SphericalOpts = exports.Point = exports.ColumnType = exports.MetadataInit = exports.MetadataColumn = exports.MetadataManager = exports.TerraFootprintSetGL = exports.TerraPointSetGL = exports.CatalogueGL = exports.FootprintSetGL = exports.HoveredFootprintDetail = exports.SphereFoV = exports.FoV = exports.HiPSDescriptor = exports.AstroViewer = void 0;
4609
+ exports.Footprint = exports.Source = exports.MeshHiPSDescriptor = exports.MeshHiPS = exports.WMTSAdapter = exports.XYZMap = exports.HiPS = exports.createColorMapFromSamples = exports.COLOR_MAP_SAMPLE_COUNT = exports.ColorMaps = exports.GeoJSONParser = exports.CoordsType = exports.FoVUtils = exports.CartesianOpts = exports.PointInitOpts = exports.AstroOpts = exports.SphericalOpts = exports.Point = exports.ColumnType = exports.MetadataInit = exports.MetadataColumn = exports.MetadataManager = exports.TerraFootprintSetGL = exports.TerraPointSetGL = exports.CatalogueGL = exports.FootprintSetGL = exports.HoveredFootprintDetail = exports.SphereFoV = exports.FoV = exports.HiPSDescriptor = exports.AstroViewer = void 0;
4440
4610
  var AstroViewer_js_1 = __webpack_require__(772);
4441
4611
  Object.defineProperty(exports, "AstroViewer", ({ enumerable: true, get: function () { return AstroViewer_js_1.AstroViewer; } }));
4442
4612
  var HiPSDescriptor_js_1 = __webpack_require__(5087);
@@ -4482,6 +4652,10 @@ var XYZMap_js_1 = __webpack_require__(1741);
4482
4652
  Object.defineProperty(exports, "XYZMap", ({ enumerable: true, get: function () { return XYZMap_js_1.XYZMap; } }));
4483
4653
  var WMTSAdapter_js_1 = __webpack_require__(3956);
4484
4654
  Object.defineProperty(exports, "WMTSAdapter", ({ enumerable: true, get: function () { return WMTSAdapter_js_1.WMTSAdapter; } }));
4655
+ var MeshHiPS_js_1 = __webpack_require__(6878);
4656
+ Object.defineProperty(exports, "MeshHiPS", ({ enumerable: true, get: function () { return MeshHiPS_js_1.MeshHiPS; } }));
4657
+ var MeshHiPSDescriptor_js_1 = __webpack_require__(847);
4658
+ Object.defineProperty(exports, "MeshHiPSDescriptor", ({ enumerable: true, get: function () { return MeshHiPSDescriptor_js_1.MeshHiPSDescriptor; } }));
4485
4659
  var Source_js_1 = __webpack_require__(146);
4486
4660
  Object.defineProperty(exports, "Source", ({ enumerable: true, get: function () { return Source_js_1.Source; } }));
4487
4661
  var Footprint_js_1 = __webpack_require__(2475);
@@ -13771,6 +13945,115 @@ class XYZRayPickingUtils {
13771
13945
  exports["default"] = XYZRayPickingUtils;
13772
13946
 
13773
13947
 
13948
+ /***/ }),
13949
+
13950
+ /***/ 2257:
13951
+ /***/ ((__unused_webpack_module, exports) => {
13952
+
13953
+
13954
+ /*
13955
+ * AstroViewer
13956
+ * Copyright (C) Fabrizio Giordano
13957
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
13958
+ */
13959
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
13960
+ exports.MeshHiPSShaderProgram = void 0;
13961
+ class MeshHiPSShaderProgram {
13962
+ _webgl;
13963
+ locations;
13964
+ _shaderProgram;
13965
+ constructor(_webgl) {
13966
+ this._webgl = _webgl;
13967
+ this.locations = {
13968
+ pMatrix: null,
13969
+ mMatrix: null,
13970
+ vMatrix: null,
13971
+ color: null,
13972
+ vertexPositionAttribute: -1,
13973
+ vertexNormalAttribute: -1,
13974
+ };
13975
+ }
13976
+ get shaderProgram() {
13977
+ const gl = this._webgl;
13978
+ if (!this._shaderProgram) {
13979
+ const program = gl.createProgram();
13980
+ if (!program)
13981
+ throw new Error('Could not create MeshHiPS shader program');
13982
+ this._shaderProgram = program;
13983
+ this.initShaders();
13984
+ }
13985
+ gl.useProgram(this._shaderProgram);
13986
+ return this._shaderProgram;
13987
+ }
13988
+ enableProgram() {
13989
+ this._webgl.useProgram(this.shaderProgram);
13990
+ }
13991
+ enableShaders(pMatrix, vMatrix, mMatrix, color) {
13992
+ const gl = this._webgl;
13993
+ const program = this.shaderProgram;
13994
+ gl.useProgram(program);
13995
+ this.locations.pMatrix = gl.getUniformLocation(program, 'uPMatrix');
13996
+ this.locations.vMatrix = gl.getUniformLocation(program, 'uVMatrix');
13997
+ this.locations.mMatrix = gl.getUniformLocation(program, 'uMMatrix');
13998
+ this.locations.color = gl.getUniformLocation(program, 'uColor');
13999
+ this.locations.vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition');
14000
+ this.locations.vertexNormalAttribute = gl.getAttribLocation(program, 'aVertexNormal');
14001
+ gl.uniformMatrix4fv(this.locations.pMatrix, false, pMatrix);
14002
+ gl.uniformMatrix4fv(this.locations.vMatrix, false, vMatrix);
14003
+ gl.uniformMatrix4fv(this.locations.mMatrix, false, mMatrix);
14004
+ gl.uniform4fv(this.locations.color, color);
14005
+ }
14006
+ initShaders() {
14007
+ const gl = this._webgl;
14008
+ const vertexShader = this.compileShader(gl.VERTEX_SHADER, `#version 300 es
14009
+ precision mediump float;
14010
+ in vec3 aVertexPosition;
14011
+ in vec3 aVertexNormal;
14012
+ uniform mat4 uPMatrix;
14013
+ uniform mat4 uVMatrix;
14014
+ uniform mat4 uMMatrix;
14015
+ out vec3 vNormal;
14016
+ void main(void) {
14017
+ vec3 worldPos = (uMMatrix * vec4(aVertexPosition, 1.0)).xyz;
14018
+ vNormal = normalize((uMMatrix * vec4(aVertexNormal, 0.0)).xyz);
14019
+ gl_Position = uPMatrix * uVMatrix * vec4(worldPos, 1.0);
14020
+ }`);
14021
+ const fragmentShader = this.compileShader(gl.FRAGMENT_SHADER, `#version 300 es
14022
+ precision mediump float;
14023
+ in vec3 vNormal;
14024
+ uniform vec4 uColor;
14025
+ out vec4 outColor;
14026
+ void main(void) {
14027
+ vec3 normal = normalize(vNormal);
14028
+ vec3 lightDir = normalize(vec3(0.45, 0.8, 0.35));
14029
+ float diffuse = max(dot(normal, lightDir), 0.0);
14030
+ float rim = pow(1.0 - max(dot(normal, vec3(0.0, 0.0, 1.0)), 0.0), 2.0);
14031
+ vec3 color = uColor.rgb * (0.24 + diffuse * 0.78) + vec3(0.16, 0.24, 0.20) * rim;
14032
+ outColor = vec4(color, uColor.a);
14033
+ }`);
14034
+ gl.attachShader(this._shaderProgram, vertexShader);
14035
+ gl.attachShader(this._shaderProgram, fragmentShader);
14036
+ gl.linkProgram(this._shaderProgram);
14037
+ if (!gl.getProgramParameter(this._shaderProgram, gl.LINK_STATUS)) {
14038
+ throw new Error(gl.getProgramInfoLog(this._shaderProgram) || 'Could not initialise MeshHiPS shaders');
14039
+ }
14040
+ }
14041
+ compileShader(type, source) {
14042
+ const gl = this._webgl;
14043
+ const shader = gl.createShader(type);
14044
+ if (!shader)
14045
+ throw new Error('Could not create MeshHiPS shader');
14046
+ gl.shaderSource(shader, source);
14047
+ gl.compileShader(shader);
14048
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
14049
+ throw new Error(gl.getShaderInfoLog(shader) || 'MeshHiPS shader compile error');
14050
+ }
14051
+ return shader;
14052
+ }
14053
+ }
14054
+ exports.MeshHiPSShaderProgram = MeshHiPSShaderProgram;
14055
+
14056
+
13774
14057
  /***/ }),
13775
14058
 
13776
14059
  /***/ 2368:
@@ -15740,6 +16023,109 @@ exports.TileBuffer = TileBuffer;
15740
16023
  // export const newTileBuffer = new TileBuffer()
15741
16024
 
15742
16025
 
16026
+ /***/ }),
16027
+
16028
+ /***/ 4322:
16029
+ /***/ ((__unused_webpack_module, exports) => {
16030
+
16031
+
16032
+ /*
16033
+ * AstroViewer
16034
+ * Copyright (C) Fabrizio Giordano
16035
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
16036
+ */
16037
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
16038
+ exports.OBJMeshParser = void 0;
16039
+ class OBJMeshParser {
16040
+ static parse(text) {
16041
+ const vertices = [];
16042
+ const indices = [];
16043
+ const normals = [];
16044
+ const lines = text.split(/\r\n|\n/);
16045
+ for (const raw of lines) {
16046
+ const line = raw.trim();
16047
+ if (!line || line.startsWith('#'))
16048
+ continue;
16049
+ if (line.startsWith('v ')) {
16050
+ const parts = line.split(/\s+/);
16051
+ if (parts.length < 4)
16052
+ continue;
16053
+ vertices.push(Number(parts[1]), Number(parts[2]), Number(parts[3]));
16054
+ normals.push(0, 0, 0);
16055
+ continue;
16056
+ }
16057
+ if (line.startsWith('f ')) {
16058
+ const face = line
16059
+ .slice(2)
16060
+ .trim()
16061
+ .split(/\s+/)
16062
+ .map((part) => Number(part.split('/')[0]))
16063
+ .filter((idx) => Number.isInteger(idx) && idx !== 0);
16064
+ if (face.length < 3)
16065
+ continue;
16066
+ const first = OBJMeshParser.resolveIndex(face[0], vertices.length / 3);
16067
+ for (let i = 1; i < face.length - 1; i++) {
16068
+ indices.push(first, OBJMeshParser.resolveIndex(face[i], vertices.length / 3), OBJMeshParser.resolveIndex(face[i + 1], vertices.length / 3));
16069
+ }
16070
+ }
16071
+ }
16072
+ OBJMeshParser.computeVertexNormals(vertices, indices, normals);
16073
+ return {
16074
+ positions: new Float32Array(vertices),
16075
+ normals: new Float32Array(normals),
16076
+ indices: new Uint32Array(indices),
16077
+ };
16078
+ }
16079
+ static computeVertexNormals(vertices, indices, normals) {
16080
+ for (let i = 0; i < indices.length; i += 3) {
16081
+ const ia = indices[i];
16082
+ const ib = indices[i + 1];
16083
+ const ic = indices[i + 2];
16084
+ const ax = vertices[ia * 3];
16085
+ const ay = vertices[ia * 3 + 1];
16086
+ const az = vertices[ia * 3 + 2];
16087
+ const bx = vertices[ib * 3];
16088
+ const by = vertices[ib * 3 + 1];
16089
+ const bz = vertices[ib * 3 + 2];
16090
+ const cx = vertices[ic * 3];
16091
+ const cy = vertices[ic * 3 + 1];
16092
+ const cz = vertices[ic * 3 + 2];
16093
+ const abx = bx - ax;
16094
+ const aby = by - ay;
16095
+ const abz = bz - az;
16096
+ const acx = cx - ax;
16097
+ const acy = cy - ay;
16098
+ const acz = cz - az;
16099
+ const nx = aby * acz - abz * acy;
16100
+ const ny = abz * acx - abx * acz;
16101
+ const nz = abx * acy - aby * acx;
16102
+ normals[ia * 3] += nx;
16103
+ normals[ia * 3 + 1] += ny;
16104
+ normals[ia * 3 + 2] += nz;
16105
+ normals[ib * 3] += nx;
16106
+ normals[ib * 3 + 1] += ny;
16107
+ normals[ib * 3 + 2] += nz;
16108
+ normals[ic * 3] += nx;
16109
+ normals[ic * 3 + 1] += ny;
16110
+ normals[ic * 3 + 2] += nz;
16111
+ }
16112
+ for (let i = 0; i < normals.length; i += 3) {
16113
+ const nx = normals[i];
16114
+ const ny = normals[i + 1];
16115
+ const nz = normals[i + 2];
16116
+ const len = Math.hypot(nx, ny, nz) || 1;
16117
+ normals[i] = nx / len;
16118
+ normals[i + 1] = ny / len;
16119
+ normals[i + 2] = nz / len;
16120
+ }
16121
+ }
16122
+ static resolveIndex(objIndex, vertexCount) {
16123
+ return objIndex > 0 ? objIndex - 1 : vertexCount + objIndex;
16124
+ }
16125
+ }
16126
+ exports.OBJMeshParser = OBJMeshParser;
16127
+
16128
+
15743
16129
  /***/ }),
15744
16130
 
15745
16131
  /***/ 4382:
@@ -16481,6 +16867,7 @@ const XYZTileRequestScheduler_js_1 = __webpack_require__(5409);
16481
16867
  const WMTSAdapter_js_1 = __webpack_require__(3956);
16482
16868
  const XYZMapDescriptor_js_1 = __webpack_require__(8868);
16483
16869
  const XYZMap_js_1 = __webpack_require__(1741);
16870
+ const MeshHiPS_js_1 = __webpack_require__(6878);
16484
16871
  const gl_matrix_1 = __webpack_require__(1961);
16485
16872
  /**
16486
16873
  * AstroSphere — main WebGL scene controller (TS port)
@@ -16507,6 +16894,7 @@ class AstroSphere {
16507
16894
  pointerDownAt = 0;
16508
16895
  _activeHiPS = null;
16509
16896
  _activeXYZ2 = null;
16897
+ _activeMeshHiPS = null;
16510
16898
  _activeBaseLayer = null;
16511
16899
  startup = true;
16512
16900
  fov;
@@ -16740,7 +17128,7 @@ class AstroSphere {
16740
17128
  }
16741
17129
  emitCameraChanged(reason) {
16742
17130
  // avoid dispatch before scene is ready
16743
- if (!this._activeHiPS)
17131
+ if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
16744
17132
  return;
16745
17133
  if (!this._healpixGrid?.fovObj)
16746
17134
  return;
@@ -17019,6 +17407,10 @@ class AstroSphere {
17019
17407
  this._activeXYZ2 = new XYZMap_js_1.XYZMap(1, [0.0, 0.0, 0.0], 0, 0, config, this._webgl);
17020
17408
  this._activeBaseLayer = "xyz";
17021
17409
  }
17410
+ activateMeshHiPS(descriptor) {
17411
+ this._activeMeshHiPS = new MeshHiPS_js_1.MeshHiPS(descriptor.meshRadius, [0.0, 0.0, 0.0], 0, 0, descriptor, this._webgl, this._healpixGrid);
17412
+ this._activeBaseLayer = "meships";
17413
+ }
17022
17414
  activateWMTS(config) {
17023
17415
  const adapter = new WMTSAdapter_js_1.WMTSAdapter(config);
17024
17416
  const xyzConfig = adapter.toXYZLayerConfig();
@@ -17199,7 +17591,7 @@ class AstroSphere {
17199
17591
  // return null
17200
17592
  }
17201
17593
  changeColorMap(cm) {
17202
- if (!this._activeHiPS && !this._activeXYZ2)
17594
+ if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
17203
17595
  return;
17204
17596
  this._selectedColorMap = cm;
17205
17597
  this._activeHiPS?.changeColorMap(cm);
@@ -17214,6 +17606,9 @@ class AstroSphere {
17214
17606
  get activeXYZ() {
17215
17607
  return this._activeXYZ2;
17216
17608
  }
17609
+ get activeMeshHiPS() {
17610
+ return this._activeMeshHiPS;
17611
+ }
17217
17612
  isLonLatGridVisible() {
17218
17613
  return this._activeXYZ2?.isLonLatGridVisible() ?? false;
17219
17614
  }
@@ -17254,12 +17649,17 @@ class AstroSphere {
17254
17649
  return null;
17255
17650
  return this._activeHiPS.getDebugStats();
17256
17651
  }
17652
+ getMeshHiPSDebugStats() {
17653
+ if (!this._activeMeshHiPS)
17654
+ return null;
17655
+ return this._activeMeshHiPS.getDebugStats();
17656
+ }
17257
17657
  draw(canvas) {
17258
17658
  if (this._refreshingStatus)
17259
17659
  return;
17260
17660
  if (!this._webgl)
17261
17661
  return;
17262
- if (!this._activeHiPS && !this._activeXYZ2)
17662
+ if (!this._activeHiPS && !this._activeXYZ2 && !this._activeMeshHiPS)
17263
17663
  return;
17264
17664
  if (!this._healpixGrid || Object.keys(this._healpixGrid).length === 0)
17265
17665
  return;
@@ -17366,6 +17766,10 @@ class AstroSphere {
17366
17766
  const visibleOrder = Math.min(this._healpixGrid.visibleorder, this._activeHiPS.maxOrder);
17367
17767
  this._healpixGrid.visibleTilesManager.computeVisiblePixels(visibleOrder, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
17368
17768
  }
17769
+ if (this._activeBaseLayer === "meships" && this._activeMeshHiPS) {
17770
+ const visibleOrder = this._activeMeshHiPS.refreshOrder(this.fov?.minFoV ?? this._healpixGrid.getMinFoV());
17771
+ this._healpixGrid.visibleTilesManager.computeVisiblePixels(visibleOrder, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
17772
+ }
17369
17773
  // DRAW HiPS
17370
17774
  const stableFovDeg = this.fov?.minFoV ?? this._healpixGrid.getMinFoV();
17371
17775
  const nowForGrid = performance.now();
@@ -17397,6 +17801,9 @@ class AstroSphere {
17397
17801
  if (this._activeBaseLayer === "xyz") {
17398
17802
  this._activeXYZ2?.draw(skyEntityDrawInput);
17399
17803
  }
17804
+ if (this._activeBaseLayer === "meships") {
17805
+ this._activeMeshHiPS?.draw(skyEntityDrawInput);
17806
+ }
17400
17807
  this._healpixGrid.draw(skyEntityDrawInput);
17401
17808
  this._equatorialGrid.draw(skyEntityDrawInput);
17402
17809
  this._webgl.enable(this._webgl.DEPTH_TEST);
@@ -17419,7 +17826,8 @@ class AstroSphere {
17419
17826
  }
17420
17827
  this.activeCatalogues.forEach((cat) => {
17421
17828
  const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
17422
- this._activeXYZ2?.getModelMatrix();
17829
+ this._activeXYZ2?.getModelMatrix() ??
17830
+ this._activeMeshHiPS?.getModelMatrix();
17423
17831
  if (activeModelMatrix) {
17424
17832
  cat.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
17425
17833
  }
@@ -17427,7 +17835,8 @@ class AstroSphere {
17427
17835
  this.emitHoveredSourceIfChanged();
17428
17836
  this.activeFootprintSets.forEach((fst) => {
17429
17837
  const activeModelMatrix = this._activeHiPS?.getModelMatrix() ??
17430
- this._activeXYZ2?.getModelMatrix();
17838
+ this._activeXYZ2?.getModelMatrix() ??
17839
+ this._activeMeshHiPS?.getModelMatrix();
17431
17840
  if (activeModelMatrix) {
17432
17841
  fst.draw(activeModelMatrix, this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
17433
17842
  }
@@ -18982,6 +19391,199 @@ class Point {
18982
19391
  exports.Point = Point;
18983
19392
 
18984
19393
 
19394
+ /***/ }),
19395
+
19396
+ /***/ 6878:
19397
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
19398
+
19399
+
19400
+ /*
19401
+ * AstroViewer
19402
+ * Copyright (C) Fabrizio Giordano
19403
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
19404
+ */
19405
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
19406
+ exports.MeshHiPS = void 0;
19407
+ const AbstractSkyEntity_js_1 = __webpack_require__(4735);
19408
+ const FoVHelper_js_1 = __webpack_require__(229);
19409
+ const MeshHiPSShaderProgram_js_1 = __webpack_require__(2257);
19410
+ const MeshHiPSTile_js_1 = __webpack_require__(8170);
19411
+ class MeshHiPS extends AbstractSkyEntity_js_1.AbstractSkyEntity {
19412
+ _descriptor;
19413
+ _healpixGrid;
19414
+ _shaderProgram;
19415
+ _tiles = new Map();
19416
+ _currentOrder;
19417
+ _visibleTiles = [];
19418
+ _coverageTiles = [];
19419
+ constructor(radius, position, xrad, yrad, _descriptor, webgl, _healpixGrid) {
19420
+ super(radius, position, xrad, yrad, _descriptor.name, webgl, false);
19421
+ this._descriptor = _descriptor;
19422
+ this._healpixGrid = _healpixGrid;
19423
+ this.initGL(webgl);
19424
+ this._shaderProgram = new MeshHiPSShaderProgram_js_1.MeshHiPSShaderProgram(webgl);
19425
+ this._shaderProgram.enableProgram();
19426
+ this._currentOrder = _descriptor.selectedOrder;
19427
+ }
19428
+ get currentOrder() {
19429
+ return this._currentOrder;
19430
+ }
19431
+ get maxOrder() {
19432
+ return this._descriptor.maxOrder;
19433
+ }
19434
+ get minOrder() {
19435
+ return this._descriptor.minOrder;
19436
+ }
19437
+ get baseURL() {
19438
+ return this._descriptor.baseUrl;
19439
+ }
19440
+ get propertiesRawText() {
19441
+ return this._descriptor.propertiesRawText;
19442
+ }
19443
+ get properties() {
19444
+ return this._descriptor.properties;
19445
+ }
19446
+ getProperty(key) {
19447
+ return this._descriptor.getProperty(key);
19448
+ }
19449
+ refreshOrder(fovDeg) {
19450
+ if (this._descriptor.fixedOrder) {
19451
+ this._currentOrder = this._descriptor.selectedOrder;
19452
+ return this._currentOrder;
19453
+ }
19454
+ const fov = Number.isFinite(fovDeg) && fovDeg > 0
19455
+ ? fovDeg
19456
+ : this._healpixGrid.getMinFoV();
19457
+ const safeFov = Number.isFinite(fov) && fov > 0 ? fov : 1e-6;
19458
+ const order = FoVHelper_js_1.fovHelper.getHiPSNorder(safeFov, this._currentOrder);
19459
+ this._currentOrder = Math.max(this._descriptor.minOrder, Math.min(this._descriptor.maxOrder, order));
19460
+ return this._currentOrder;
19461
+ }
19462
+ draw(input) {
19463
+ const vMatrix = input.camera.getCameraMatrix();
19464
+ if (!vMatrix || !input.pMatrix)
19465
+ return;
19466
+ this.refreshOrder(input.fovDeg);
19467
+ this._visibleTiles = this.resolveVisibleTiles();
19468
+ this._coverageTiles = this.resolveCoverageTiles(this._visibleTiles);
19469
+ this.ensureTiles(this._coverageTiles);
19470
+ this.evictCached();
19471
+ const gl = this._webgl;
19472
+ const pMatrix = input.pMatrix;
19473
+ const mMatrix = this.getModelMatrix();
19474
+ const wasCullFace = gl.isEnabled(gl.CULL_FACE);
19475
+ const wasDepthTest = gl.isEnabled(gl.DEPTH_TEST);
19476
+ const wasDepthMask = gl.getParameter(gl.DEPTH_WRITEMASK);
19477
+ const previousDepthFunc = gl.getParameter(gl.DEPTH_FUNC);
19478
+ gl.enable(gl.DEPTH_TEST);
19479
+ gl.depthMask(true);
19480
+ gl.depthFunc(gl.LEQUAL);
19481
+ gl.disable(gl.CULL_FACE);
19482
+ const byOrder = this.groupTilesByOrder(this._coverageTiles);
19483
+ const orders = Array.from(byOrder.keys()).sort((a, b) => a - b);
19484
+ for (const order of orders) {
19485
+ for (const coord of byOrder.get(order) ?? []) {
19486
+ this._tiles.get(this.tileKey(coord))?.draw(pMatrix, vMatrix, mMatrix, this._descriptor.color, this._descriptor.wireframe);
19487
+ }
19488
+ }
19489
+ if (wasCullFace)
19490
+ gl.enable(gl.CULL_FACE);
19491
+ if (!wasDepthTest)
19492
+ gl.disable(gl.DEPTH_TEST);
19493
+ gl.depthFunc(previousDepthFunc);
19494
+ gl.depthMask(wasDepthMask);
19495
+ }
19496
+ getDebugStats() {
19497
+ const tiles = Array.from(this._tiles.values());
19498
+ return {
19499
+ activeBaseLayer: 'meships',
19500
+ meshHiPSName: this._descriptor.name,
19501
+ meshHiPSUrl: this._descriptor.baseUrl,
19502
+ currentOrder: this._currentOrder,
19503
+ visibleTileCount: this._visibleTiles.length,
19504
+ coverageTileCount: this._coverageTiles.length,
19505
+ cacheSize: this._tiles.size,
19506
+ readyTileCount: tiles.filter((tile) => tile.ready).length,
19507
+ loadingTileCount: tiles.filter((tile) => tile.loading).length,
19508
+ failedTileCount: tiles.filter((tile) => tile.failed).length,
19509
+ };
19510
+ }
19511
+ resolveVisibleTiles() {
19512
+ const manager = this._healpixGrid.visibleTilesManager;
19513
+ const byOrder = manager?.visibleTilesByOrder;
19514
+ const pixels = byOrder?.order === this._currentOrder && Array.isArray(byOrder.pixels)
19515
+ ? byOrder.pixels
19516
+ : [];
19517
+ if (pixels.length > 0) {
19518
+ return pixels.map((ipix) => ({ order: this._currentOrder, ipix }));
19519
+ }
19520
+ const tileCount = 12 * 4 ** this._currentOrder;
19521
+ return Array.from({ length: tileCount }, (_, ipix) => ({ order: this._currentOrder, ipix }));
19522
+ }
19523
+ resolveCoverageTiles(visibleTiles) {
19524
+ const tiles = new Map();
19525
+ const add = (coord) => {
19526
+ if (coord.order < this._descriptor.minOrder || coord.order > this._descriptor.maxOrder)
19527
+ return;
19528
+ tiles.set(this.tileKey(coord), coord);
19529
+ };
19530
+ for (const coord of visibleTiles) {
19531
+ add(coord);
19532
+ for (let order = coord.order - 1; order >= this._descriptor.minOrder; order--) {
19533
+ const shift = 2 * (coord.order - order);
19534
+ add({ order, ipix: coord.ipix >> shift });
19535
+ }
19536
+ }
19537
+ const manager = this._healpixGrid.visibleTilesManager;
19538
+ const ancestorsMap = manager?.ancestorsMap;
19539
+ if (ancestorsMap) {
19540
+ for (const [order, ipixes] of ancestorsMap) {
19541
+ if (order < this._descriptor.minOrder || order > this._descriptor.maxOrder)
19542
+ continue;
19543
+ for (const ipix of ipixes)
19544
+ add({ order, ipix });
19545
+ }
19546
+ }
19547
+ return Array.from(tiles.values());
19548
+ }
19549
+ groupTilesByOrder(coords) {
19550
+ const byOrder = new Map();
19551
+ for (const coord of coords) {
19552
+ const list = byOrder.get(coord.order) ?? [];
19553
+ list.push(coord);
19554
+ byOrder.set(coord.order, list);
19555
+ }
19556
+ return byOrder;
19557
+ }
19558
+ ensureTiles(coords) {
19559
+ for (const coord of coords) {
19560
+ const key = this.tileKey(coord);
19561
+ if (this._tiles.has(key))
19562
+ continue;
19563
+ this._tiles.set(key, new MeshHiPSTile_js_1.MeshHiPSTile(coord, this._descriptor.getTileUrl(coord.order, coord.ipix), this._webgl, this._shaderProgram));
19564
+ }
19565
+ }
19566
+ evictCached() {
19567
+ const maxCached = this._descriptor.maxCachedTiles;
19568
+ if (this._tiles.size <= maxCached)
19569
+ return;
19570
+ const visibleKeys = new Set(this._coverageTiles.map((coord) => this.tileKey(coord)));
19571
+ const evictable = Array.from(this._tiles.entries())
19572
+ .filter(([key]) => !visibleKeys.has(key))
19573
+ .sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt);
19574
+ while (this._tiles.size > maxCached && evictable.length > 0) {
19575
+ const [key, tile] = evictable.shift();
19576
+ tile.dispose();
19577
+ this._tiles.delete(key);
19578
+ }
19579
+ }
19580
+ tileKey(coord) {
19581
+ return `${coord.order}/${coord.ipix}`;
19582
+ }
19583
+ }
19584
+ exports.MeshHiPS = MeshHiPS;
19585
+
19586
+
18985
19587
  /***/ }),
18986
19588
 
18987
19589
  /***/ 6937:
@@ -20452,6 +21054,165 @@ var CoordsType;
20452
21054
  // export default CoordsType;
20453
21055
 
20454
21056
 
21057
+ /***/ }),
21058
+
21059
+ /***/ 8170:
21060
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
21061
+
21062
+
21063
+ /*
21064
+ * AstroViewer
21065
+ * Copyright (C) Fabrizio Giordano
21066
+ * SPDX-License-Identifier: LicenseRef-AstroViewer-Dual-License
21067
+ */
21068
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
21069
+ exports.MeshHiPSTile = void 0;
21070
+ const OBJMeshParser_js_1 = __webpack_require__(4322);
21071
+ class MeshHiPSTile {
21072
+ coord;
21073
+ _url;
21074
+ _webgl;
21075
+ _shaderProgram;
21076
+ _gpuMesh = null;
21077
+ _ready = false;
21078
+ _loading = false;
21079
+ _failed = false;
21080
+ _lastUsedAt = 0;
21081
+ _createdAt = Date.now();
21082
+ constructor(coord, _url, _webgl, _shaderProgram) {
21083
+ this.coord = coord;
21084
+ this._url = _url;
21085
+ this._webgl = _webgl;
21086
+ this._shaderProgram = _shaderProgram;
21087
+ void this.load();
21088
+ }
21089
+ get ready() {
21090
+ return this._ready;
21091
+ }
21092
+ get loading() {
21093
+ return this._loading;
21094
+ }
21095
+ get failed() {
21096
+ return this._failed;
21097
+ }
21098
+ get lastUsedAt() {
21099
+ return this._lastUsedAt;
21100
+ }
21101
+ get createdAt() {
21102
+ return this._createdAt;
21103
+ }
21104
+ touch() {
21105
+ this._lastUsedAt = Date.now();
21106
+ }
21107
+ draw(pMatrix, vMatrix, mMatrix, color, wireframe) {
21108
+ this.touch();
21109
+ if (!this._ready || !this._gpuMesh)
21110
+ return false;
21111
+ const gl = this._webgl;
21112
+ this._shaderProgram.enableShaders(pMatrix, vMatrix, mMatrix, color);
21113
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._gpuMesh.positionBuffer);
21114
+ gl.vertexAttribPointer(this._shaderProgram.locations.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
21115
+ gl.enableVertexAttribArray(this._shaderProgram.locations.vertexPositionAttribute);
21116
+ if (this._shaderProgram.locations.vertexNormalAttribute >= 0) {
21117
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._gpuMesh.normalBuffer);
21118
+ gl.vertexAttribPointer(this._shaderProgram.locations.vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
21119
+ gl.enableVertexAttribArray(this._shaderProgram.locations.vertexNormalAttribute);
21120
+ }
21121
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, wireframe ? this._gpuMesh.lineIndexBuffer : this._gpuMesh.indexBuffer);
21122
+ gl.drawElements(wireframe ? gl.LINES : gl.TRIANGLES, wireframe ? this._gpuMesh.lineIndexCount : this._gpuMesh.indexCount, this._gpuMesh.indexType, 0);
21123
+ gl.disableVertexAttribArray(this._shaderProgram.locations.vertexPositionAttribute);
21124
+ if (this._shaderProgram.locations.vertexNormalAttribute >= 0) {
21125
+ gl.disableVertexAttribArray(this._shaderProgram.locations.vertexNormalAttribute);
21126
+ }
21127
+ return true;
21128
+ }
21129
+ dispose() {
21130
+ const gl = this._webgl;
21131
+ if (this._gpuMesh?.positionBuffer)
21132
+ gl.deleteBuffer(this._gpuMesh.positionBuffer);
21133
+ if (this._gpuMesh?.normalBuffer)
21134
+ gl.deleteBuffer(this._gpuMesh.normalBuffer);
21135
+ if (this._gpuMesh?.indexBuffer)
21136
+ gl.deleteBuffer(this._gpuMesh.indexBuffer);
21137
+ if (this._gpuMesh?.lineIndexBuffer)
21138
+ gl.deleteBuffer(this._gpuMesh.lineIndexBuffer);
21139
+ this._gpuMesh = null;
21140
+ this._ready = false;
21141
+ this._loading = false;
21142
+ }
21143
+ async load() {
21144
+ if (this._loading || this._ready)
21145
+ return;
21146
+ this._loading = true;
21147
+ try {
21148
+ const resp = await fetch(this._url);
21149
+ if (!resp.ok)
21150
+ throw new Error(`HTTP ${resp.status} fetching ${this._url}`);
21151
+ const mesh = OBJMeshParser_js_1.OBJMeshParser.parse(await resp.text());
21152
+ this._gpuMesh = this.uploadMesh(mesh);
21153
+ this._ready = true;
21154
+ this._failed = false;
21155
+ }
21156
+ catch (error) {
21157
+ console.warn('[MeshHiPSTile] load failed', this._url, error);
21158
+ this._failed = true;
21159
+ this._ready = false;
21160
+ }
21161
+ finally {
21162
+ this._loading = false;
21163
+ }
21164
+ }
21165
+ uploadMesh(mesh) {
21166
+ const gl = this._webgl;
21167
+ const positionBuffer = gl.createBuffer();
21168
+ const normalBuffer = gl.createBuffer();
21169
+ const indexBuffer = gl.createBuffer();
21170
+ const lineIndexBuffer = gl.createBuffer();
21171
+ if (!positionBuffer || !normalBuffer || !indexBuffer || !lineIndexBuffer) {
21172
+ throw new Error(`Could not create MeshHiPS buffers for ${this.key}`);
21173
+ }
21174
+ const lineIndices = this.buildLineIndices(mesh.indices);
21175
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
21176
+ gl.bufferData(gl.ARRAY_BUFFER, mesh.positions, gl.STATIC_DRAW);
21177
+ gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
21178
+ gl.bufferData(gl.ARRAY_BUFFER, mesh.normals, gl.STATIC_DRAW);
21179
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
21180
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, mesh.indices, gl.STATIC_DRAW);
21181
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, lineIndexBuffer);
21182
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, lineIndices, gl.STATIC_DRAW);
21183
+ return {
21184
+ positionBuffer,
21185
+ normalBuffer,
21186
+ indexBuffer,
21187
+ lineIndexBuffer,
21188
+ indexCount: mesh.indices.length,
21189
+ lineIndexCount: lineIndices.length,
21190
+ indexType: gl.UNSIGNED_INT,
21191
+ };
21192
+ }
21193
+ buildLineIndices(indices) {
21194
+ const lines = new Uint32Array(indices.length * 2);
21195
+ let out = 0;
21196
+ for (let i = 0; i < indices.length; i += 3) {
21197
+ const a = indices[i];
21198
+ const b = indices[i + 1];
21199
+ const c = indices[i + 2];
21200
+ lines[out++] = a;
21201
+ lines[out++] = b;
21202
+ lines[out++] = b;
21203
+ lines[out++] = c;
21204
+ lines[out++] = c;
21205
+ lines[out++] = a;
21206
+ }
21207
+ return lines;
21208
+ }
21209
+ get key() {
21210
+ return `${this.coord.order}/${this.coord.ipix}`;
21211
+ }
21212
+ }
21213
+ exports.MeshHiPSTile = MeshHiPSTile;
21214
+
21215
+
20455
21216
  /***/ }),
20456
21217
 
20457
21218
  /***/ 8256: