setiastrosuitepro 1.8.0.post3__py3-none-any.whl → 1.8.2__py3-none-any.whl

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.

Potentially problematic release.


This version of setiastrosuitepro might be problematic. Click here for more details.

Files changed (43) hide show
  1. setiastro/images/finderchart.png +0 -0
  2. setiastro/saspro/__main__.py +41 -39
  3. setiastro/saspro/_generated/build_info.py +2 -2
  4. setiastro/saspro/abe.py +1 -1
  5. setiastro/saspro/blink_comparator_pro.py +3 -1
  6. setiastro/saspro/bright_stars.py +305 -0
  7. setiastro/saspro/continuum_subtract.py +2 -1
  8. setiastro/saspro/cosmicclarity_engines/darkstar_engine.py +22 -2
  9. setiastro/saspro/cosmicclarity_engines/denoise_engine.py +68 -15
  10. setiastro/saspro/cosmicclarity_engines/satellite_engine.py +7 -3
  11. setiastro/saspro/cosmicclarity_engines/sharpen_engine.py +371 -98
  12. setiastro/saspro/cosmicclarity_engines/superres_engine.py +1 -0
  13. setiastro/saspro/cosmicclarity_preset.py +2 -1
  14. setiastro/saspro/doc_manager.py +8 -0
  15. setiastro/saspro/exoplanet_detector.py +22 -17
  16. setiastro/saspro/finder_chart.py +1639 -0
  17. setiastro/saspro/gui/main_window.py +36 -14
  18. setiastro/saspro/gui/mixins/menu_mixin.py +2 -0
  19. setiastro/saspro/gui/mixins/toolbar_mixin.py +9 -1
  20. setiastro/saspro/legacy/image_manager.py +18 -4
  21. setiastro/saspro/legacy/xisf.py +3 -3
  22. setiastro/saspro/main_helpers.py +18 -0
  23. setiastro/saspro/memory_utils.py +18 -14
  24. setiastro/saspro/model_manager.py +65 -0
  25. setiastro/saspro/model_workers.py +58 -24
  26. setiastro/saspro/ops/settings.py +45 -8
  27. setiastro/saspro/planetprojection.py +68 -36
  28. setiastro/saspro/resources.py +193 -175
  29. setiastro/saspro/runtime_torch.py +622 -137
  30. setiastro/saspro/sfcc.py +5 -3
  31. setiastro/saspro/stacking_suite.py +4 -3
  32. setiastro/saspro/star_alignment.py +266 -212
  33. setiastro/saspro/texture_clarity.py +1 -1
  34. setiastro/saspro/widgets/image_utils.py +12 -4
  35. setiastro/saspro/widgets/spinboxes.py +5 -7
  36. setiastro/saspro/wimi.py +2 -1
  37. setiastro/saspro/xisf.py +3 -3
  38. {setiastrosuitepro-1.8.0.post3.dist-info → setiastrosuitepro-1.8.2.dist-info}/METADATA +4 -4
  39. {setiastrosuitepro-1.8.0.post3.dist-info → setiastrosuitepro-1.8.2.dist-info}/RECORD +43 -40
  40. {setiastrosuitepro-1.8.0.post3.dist-info → setiastrosuitepro-1.8.2.dist-info}/WHEEL +0 -0
  41. {setiastrosuitepro-1.8.0.post3.dist-info → setiastrosuitepro-1.8.2.dist-info}/entry_points.txt +0 -0
  42. {setiastrosuitepro-1.8.0.post3.dist-info → setiastrosuitepro-1.8.2.dist-info}/licenses/LICENSE +0 -0
  43. {setiastrosuitepro-1.8.0.post3.dist-info → setiastrosuitepro-1.8.2.dist-info}/licenses/license.txt +0 -0
@@ -2175,6 +2175,52 @@ class PlanetProjectionDialog(QDialog):
2175
2175
  self._show_stereo_pair(cross_eye=cross_eye)
2176
2176
  return
2177
2177
 
2178
+ # ---- GALAXY TOP-DOWN (early exit) ----
2179
+ # IMPORTANT: do this BEFORE any ROI crop, otherwise huge galaxies get clipped by ROI sizing.
2180
+ is_galaxy = (ptype == 3) or (mode == 5) # planet_type==Galaxy OR output==Galaxy Polar View
2181
+ if is_galaxy:
2182
+ def to01(x):
2183
+ if x.dtype == np.uint8:
2184
+ return x.astype(np.float32) / 255.0
2185
+ if x.dtype == np.uint16:
2186
+ return x.astype(np.float32) / 65535.0
2187
+ return x.astype(np.float32, copy=False)
2188
+
2189
+ roi = img[..., :3] # FULL IMAGE
2190
+ cx0 = float(cx) # FULL-IMAGE coords
2191
+ cy0 = float(cy)
2192
+ roi01 = to01(roi)
2193
+
2194
+ pa = float(self.spin_ring_pa.value()) # reuse ring PA widget as galaxy PA
2195
+ tilt = float(self.spin_ring_tilt.value()) # reuse ring tilt widget as galaxy b/a
2196
+
2197
+ # output size: tied to full image (clamped)
2198
+ out_size = int(max(256, min(2400, max(roi.shape[0], roi.shape[1]))))
2199
+
2200
+ try:
2201
+ top8 = deproject_galaxy_topdown_u8(
2202
+ roi01,
2203
+ cx0=cx0, cy0=cy0,
2204
+ rpx=float(r),
2205
+ pa_deg=pa,
2206
+ tilt=tilt,
2207
+ out_size=out_size,
2208
+ )
2209
+ except Exception as e:
2210
+ QMessageBox.warning(self, "Galaxy Polar View", f"Failed to deproject galaxy:\n{e}")
2211
+ return
2212
+
2213
+ # push single-frame output
2214
+ self._left = None
2215
+ self._right = None
2216
+ self._wiggle_frames = None
2217
+ self._wiggle_state = False
2218
+
2219
+ self._last_preview_u8 = top8
2220
+ self._push_preview_u8(top8)
2221
+ return
2222
+
2223
+
2178
2224
  # ---- Saturn rings ROI expansion (only increases s) ----
2179
2225
  is_saturn = (self.cmb_planet_type.currentIndex() == 1)
2180
2226
  rings_on = bool(is_saturn and getattr(self, "chk_rings", None) is not None and self.chk_rings.isChecked())
@@ -2209,6 +2255,28 @@ class PlanetProjectionDialog(QDialog):
2209
2255
  y1 = min(Hfull, y0 + s)
2210
2256
 
2211
2257
  roi = img[y0:y1, x0:x1, :3]
2258
+ # ---- GALAXY ROI expansion (ensure full projected ellipse fits) ----
2259
+ if ptype == 3:
2260
+ tilt = float(self.spin_ring_tilt.value())
2261
+ pa = float(self.spin_ring_pa.value())
2262
+
2263
+ tilt = float(np.clip(tilt, 0.02, 1.0))
2264
+
2265
+ # ellipse in SOURCE pixels
2266
+ a = float(r) # semi-major
2267
+ b = max(1.0, a * tilt) # semi-minor
2268
+
2269
+ th = np.deg2rad(pa)
2270
+ cth, sth = np.cos(th), np.sin(th)
2271
+
2272
+ # bounding half-extents of rotated ellipse
2273
+ dx = np.sqrt((a * cth) ** 2 + (b * sth) ** 2)
2274
+ dy = np.sqrt((a * sth) ** 2 + (b * cth) ** 2)
2275
+ need_half = float(max(dx, dy))
2276
+
2277
+ margin = 12.0
2278
+ s_need = int(np.ceil(2.0 * (need_half + margin)))
2279
+ s = max(s, s_need)
2212
2280
 
2213
2281
  # ---- disk mask (ROI coords) ----
2214
2282
  H0, W0 = roi.shape[:2]
@@ -2226,42 +2294,6 @@ class PlanetProjectionDialog(QDialog):
2226
2294
 
2227
2295
  theta = float(self.spin_theta.value())
2228
2296
 
2229
- # ---- GALAXY TOP-DOWN (early exit) ----
2230
- is_galaxy = (ptype == 3) or (mode == 5) # planet_type==Galaxy OR output==Galaxy Polar View
2231
-
2232
- if is_galaxy:
2233
- # Galaxy wants the ROI disk params (cx0, cy0, r) + PA/tilt
2234
- roi01 = to01(roi)
2235
-
2236
- pa = float(self.spin_ring_pa.value()) # reuse ring PA widget as galaxy PA
2237
- tilt = float(self.spin_ring_tilt.value()) # reuse ring tilt widget as galaxy b/a
2238
-
2239
- # choose output size: use ROI size or clamp to something reasonable
2240
- out_size = int(max(256, min(2000, max(roi.shape[0], roi.shape[1]))))
2241
-
2242
- try:
2243
- top8 = deproject_galaxy_topdown_u8(
2244
- roi01,
2245
- cx0=float(cx0), cy0=float(cy0),
2246
- rpx=float(r),
2247
- pa_deg=pa,
2248
- tilt=tilt,
2249
- out_size=out_size,
2250
- )
2251
- except Exception as e:
2252
- QMessageBox.warning(self, "Galaxy Polar View", f"Failed to deproject galaxy:\n{e}")
2253
- return
2254
-
2255
- # push single-frame output
2256
- self._left = None
2257
- self._right = None
2258
- self._wiggle_frames = None
2259
- self._wiggle_state = False
2260
-
2261
- self._last_preview_u8 = top8
2262
- self._push_preview_u8(top8)
2263
- return
2264
-
2265
2297
  # ---- BODY (sphere reprojection) ----
2266
2298
  interp = cv2.INTER_LANCZOS4
2267
2299
  left_w, right_w, maskL, maskR = make_stereo_pair(
@@ -340,6 +340,7 @@ class Icons:
340
340
  DEBAYER = property(lambda self: _resource_path('debayer.png'))
341
341
  FUNCTION_BUNDLES = property(lambda self: _resource_path('functionbundle.png'))
342
342
  VIEW_BUNDLES = property(lambda self: _resource_path('viewbundle.png'))
343
+ FINDER_CHART = property(lambda self: _resource_path('finderchart.png'))
343
344
 
344
345
  # Singleton instances for easy access
345
346
  _icons_instance = None
@@ -396,157 +397,178 @@ def get_data_path(name: str) -> str:
396
397
  """
397
398
  return _resource_path(name)
398
399
 
400
+ # ---------------- Legacy compatibility (LAZY) ----------------
401
+ # These names match the original module-level variables used in older code.
402
+
403
+ _LEGACY_ICON_MAP = {
404
+ 'icon_path': 'astrosuitepro.png',
405
+ 'windowslogo_path': 'astrosuitepro.ico',
406
+ 'green_path': 'green.png',
407
+ 'neutral_path': 'neutral.png',
408
+ 'whitebalance_path': 'whitebalance.png',
409
+ 'texture_clarity_path': 'TextureClarity.svg',
410
+ 'morpho_path': 'morpho.png',
411
+ 'clahe_path': 'clahe.png',
412
+ 'starnet_path': 'starnet.png',
413
+ 'staradd_path': 'staradd.png',
414
+ 'LExtract_path': 'LExtract.png',
415
+ 'LInsert_path': 'LInsert.png',
416
+ 'slot0_path': 'slot0.png',
417
+ 'slot1_path': 'slot1.png',
418
+ 'slot2_path': 'slot2.png',
419
+ 'slot3_path': 'slot3.png',
420
+ 'slot4_path': 'slot4.png',
421
+ 'slot5_path': 'slot5.png',
422
+ 'slot6_path': 'slot6.png',
423
+ 'slot7_path': 'slot7.png',
424
+ 'slot8_path': 'slot8.png',
425
+ 'slot9_path': 'slot9.png',
426
+ 'acv_icon_path': 'acv_icon.png',
427
+
428
+ 'moon_new_path': 'new_moon.png',
429
+ 'moon_waxing_crescent_1_path': 'waxing_crescent_1.png',
430
+ 'moon_waxing_crescent_2_path': 'waxing_crescent_2.png',
431
+ 'moon_waxing_crescent_3_path': 'waxing_crescent_3.png',
432
+ 'moon_waxing_crescent_4_path': 'waxing_crescent_4.png',
433
+ 'moon_waxing_crescent_5_path': 'waxing_crescent_5.png',
434
+ 'moon_first_quarter_path': 'first_quarter.png',
435
+ 'moon_waxing_gibbous_1_path': 'waxing_gibbous_1.png',
436
+ 'moon_waxing_gibbous_2_path': 'waxing_gibbous_2.png',
437
+ 'moon_waxing_gibbous_3_path': 'waxing_gibbous_3.png',
438
+ 'moon_waxing_gibbous_4_path': 'waxing_gibbous_4.png',
439
+ 'moon_waxing_gibbous_5_path': 'waxing_gibbous_5.png',
440
+ 'moon_full_path': 'full_moon.png',
441
+ 'moon_waning_gibbous_1_path': 'waning_gibbous_1.png',
442
+ 'moon_waning_gibbous_2_path': 'waning_gibbous_2.png',
443
+ 'moon_waning_gibbous_3_path': 'waning_gibbous_3.png',
444
+ 'moon_waning_gibbous_4_path': 'waning_gibbous_4.png',
445
+ 'moon_waning_gibbous_5_path': 'waning_gibbous_5.png',
446
+ 'moon_last_quarter_path': 'last_quarter.png',
447
+ 'moon_waning_crescent_1_path': 'waning_crescent_1.png',
448
+ 'moon_waning_crescent_2_path': 'waning_crescent_2.png',
449
+ 'moon_waning_crescent_3_path': 'waning_crescent_3.png',
450
+ 'moon_waning_crescent_4_path': 'waning_crescent_4.png',
451
+ 'moon_waning_crescent_5_path': 'waning_crescent_5.png',
452
+
453
+ 'rgbcombo_path': 'rgbcombo.png',
454
+ 'rgbextract_path': 'rgbextract.png',
455
+ 'copyslot_path': 'copyslot.png',
456
+ 'graxperticon_path': 'graxpert.png',
457
+ 'cropicon_path': 'cropicon.png',
458
+ 'openfile_path': 'openfile.png',
459
+ 'abeicon_path': 'abeicon.png',
460
+ 'undoicon_path': 'undoicon.png',
461
+ 'redoicon_path': 'redoicon.png',
462
+ 'blastericon_path': 'blaster.png',
463
+ 'clonestampicon_path': 'clonestamp.png',
464
+ 'hdr_path': 'hdr.png',
465
+ 'invert_path': 'invert.png',
466
+ 'fliphorizontal_path': 'fliphorizontal.png',
467
+ 'flipvertical_path': 'flipvertical.png',
468
+ 'rotateclockwise_path': 'rotateclockwise.png',
469
+ 'rotatecounterclockwise_path': 'rotatecounterclockwise.png',
470
+ 'rotate180_path': 'rotate180.png',
471
+ 'rotatearbitrary_path': 'rotatearbitrary.png',
472
+ 'maskcreate_path': 'maskcreate.png',
473
+ 'maskapply_path': 'maskapply.png',
474
+ 'maskremove_path': 'maskremove.png',
475
+ 'pixelmath_path': 'pixelmath.png',
476
+ 'histogram_path': 'histogram.png',
477
+ 'mosaic_path': 'mosaic.png',
478
+ 'rescale_path': 'rescale.png',
479
+ 'staralign_path': 'staralign.png',
480
+ 'mask_path': 'maskapply.png',
481
+ 'platesolve_path': 'platesolve.png',
482
+ 'psf_path': 'psf.png',
483
+ 'supernova_path': 'supernova.png',
484
+ 'starregistration_path': 'starregistration.png',
485
+ 'stacking_path': 'stacking.png',
486
+ 'pedestal_icon_path': 'pedestal.png',
487
+ 'starspike_path': 'starspike.png',
488
+ 'astrospike_path': 'Astro_Spikes.png',
489
+ 'aperture_path': 'aperture.png',
490
+ 'jwstpupil_path': 'jwstpupil.png',
491
+ 'signature_icon_path': 'pen.png',
492
+ 'livestacking_path': 'livestacking.png',
493
+ 'hrdiagram_path': 'HRDiagram.png',
494
+ 'convoicon_path': 'convo.png',
495
+ 'spcc_icon_path': 'spcc.png',
496
+
497
+ 'exoicon_path': 'exoicon.png',
498
+ 'peeker_icon': 'gridicon.png',
499
+ 'dse_icon_path': 'dse.png',
500
+ 'isophote_path': 'isophote.png',
501
+ 'statstretch_path': 'statstretch.png',
502
+ 'starstretch_path': 'starstretch.png',
503
+ 'curves_path': 'curves.png',
504
+ 'disk_path': 'disk.png',
505
+ 'uhs_path': 'uhs.png',
506
+ 'blink_path': 'blink.png',
507
+ 'ppp_path': 'ppp.png',
508
+ 'nbtorgb_path': 'nbtorgb.png',
509
+ 'freqsep_path': 'freqsep.png',
510
+ 'multiscale_decomp_path': 'multiscale_decomp.png',
511
+ 'contsub_path': 'contsub.png',
512
+ 'halo_path': 'halo.png',
513
+ 'cosmic_path': 'cosmic.png',
514
+ 'satellite_path': 'cosmicsat.png',
515
+ 'imagecombine_path': 'imagecombine.png',
516
+ 'wrench_path': 'wrench_icon.png',
517
+ 'eye_icon_path': 'eye.png',
518
+ 'disk_icon_path': 'disk.png',
519
+ 'nuke_path': 'nuke.png',
520
+ 'hubble_path': 'hubble.png',
521
+ 'collage_path': 'collage.png',
522
+ 'annotated_path': 'annotated.png',
523
+ 'colorwheel_path': 'colorwheel.png',
524
+ 'narrowbandnormalization_path': 'narrowbandnormalization.png',
525
+ 'font_path': 'font.png',
526
+ 'csv_icon_path': 'cvs.png',
527
+ 'wims_path': 'wims.png',
528
+ 'wimi_path': 'wimi_icon_256x256.png',
529
+ 'linearfit_path': 'linearfit.png',
530
+ 'debayer_path': 'debayer.png',
531
+ 'aberration_path': 'aberration.png',
532
+ 'functionbundles_path': 'functionbundle.png',
533
+ 'planetarystacker_path': 'planetarystacker.png',
534
+ 'viewbundles_path': 'viewbundle.png',
535
+ 'selectivecolor_path': 'selectivecolor.png',
536
+ 'rgbalign_path': 'rgbalign.png',
537
+ 'background_path': 'background.png',
538
+ 'script_icon_path': 'script.png',
539
+ 'planetprojection_path': '3dplanet.png',
540
+ 'finderchart_path': 'finderchart.png',
541
+ }
542
+
543
+ _LEGACY_DATA_MAP = {
544
+ 'sasp_data_path': 'data/SASP_data.fits',
545
+ 'astrobin_filters_csv_path': 'data/catalogs/astrobin_filters.csv',
546
+ 'spinner_path': 'spinner.gif',
547
+ }
548
+
549
+ def __getattr__(name: str):
550
+ # --- legacy paths (lazy) ---
551
+ if name in _LEGACY_ICON_MAP:
552
+ return get_icon_path(_LEGACY_ICON_MAP[name])
553
+ if name in _LEGACY_DATA_MAP:
554
+ return get_data_path(_LEGACY_DATA_MAP[name])
555
+
556
+ # --- special exports ---
557
+ if name == 'background_startup_path':
558
+ return _resource_path('Background_startup.jpg')
559
+ if name == 'resource_monitor_qml':
560
+ return _resource_path(os.path.join("qml", "ResourceMonitor.qml"))
561
+
562
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
563
+
564
+ def __dir__():
565
+ return (
566
+ list(globals().keys())
567
+ + list(_LEGACY_ICON_MAP.keys())
568
+ + list(_LEGACY_DATA_MAP.keys())
569
+ + ['background_startup_path', 'resource_monitor_qml']
570
+ )
399
571
 
400
- # Legacy compatibility: export paths as module-level variables
401
- # These match the original variable names in setiastrosuitepro.py
402
- def _init_legacy_paths():
403
- """Initialize legacy path variables for backward compatibility."""
404
- return {
405
- 'icon_path': get_icon_path('astrosuitepro.png'),
406
- 'windowslogo_path': get_icon_path('astrosuitepro.ico'),
407
- 'green_path': get_icon_path('green.png'),
408
- 'neutral_path': get_icon_path('neutral.png'),
409
- 'whitebalance_path': get_icon_path('whitebalance.png'),
410
- 'texture_clarity_path': get_icon_path('TextureClarity.svg'),
411
- 'morpho_path': get_icon_path('morpho.png'),
412
- 'clahe_path': get_icon_path('clahe.png'),
413
- 'starnet_path': get_icon_path('starnet.png'),
414
- 'staradd_path': get_icon_path('staradd.png'),
415
- 'LExtract_path': get_icon_path('LExtract.png'),
416
- 'LInsert_path': get_icon_path('LInsert.png'),
417
- 'slot0_path': get_icon_path('slot0.png'),
418
- 'slot1_path': get_icon_path('slot1.png'),
419
- 'slot2_path': get_icon_path('slot2.png'),
420
- 'slot3_path': get_icon_path('slot3.png'),
421
- 'slot4_path': get_icon_path('slot4.png'),
422
- 'slot5_path': get_icon_path('slot5.png'),
423
- 'slot6_path': get_icon_path('slot6.png'),
424
- 'slot7_path': get_icon_path('slot7.png'),
425
- 'slot8_path': get_icon_path('slot8.png'),
426
- 'slot9_path': get_icon_path('slot9.png'),
427
- 'acv_icon_path': get_icon_path('acv_icon.png'),
428
-
429
- 'moon_new_path': get_icon_path('new_moon.png'),
430
- 'moon_waxing_crescent_1_path': get_icon_path('waxing_crescent_1.png'),
431
- 'moon_waxing_crescent_2_path': get_icon_path('waxing_crescent_2.png'),
432
- 'moon_waxing_crescent_3_path': get_icon_path('waxing_crescent_3.png'),
433
- 'moon_waxing_crescent_4_path': get_icon_path('waxing_crescent_4.png'),
434
- 'moon_waxing_crescent_5_path': get_icon_path('waxing_crescent_5.png'),
435
-
436
- 'moon_first_quarter_path': get_icon_path('first_quarter.png'),
437
-
438
- 'moon_waxing_gibbous_1_path': get_icon_path('waxing_gibbous_1.png'),
439
- 'moon_waxing_gibbous_2_path': get_icon_path('waxing_gibbous_2.png'),
440
- 'moon_waxing_gibbous_3_path': get_icon_path('waxing_gibbous_3.png'),
441
- 'moon_waxing_gibbous_4_path': get_icon_path('waxing_gibbous_4.png'),
442
- 'moon_waxing_gibbous_5_path': get_icon_path('waxing_gibbous_5.png'),
443
-
444
- 'moon_full_path': get_icon_path('full_moon.png'),
445
-
446
- 'moon_waning_gibbous_1_path': get_icon_path('waning_gibbous_1.png'),
447
- 'moon_waning_gibbous_2_path': get_icon_path('waning_gibbous_2.png'),
448
- 'moon_waning_gibbous_3_path': get_icon_path('waning_gibbous_3.png'),
449
- 'moon_waning_gibbous_4_path': get_icon_path('waning_gibbous_4.png'),
450
- 'moon_waning_gibbous_5_path': get_icon_path('waning_gibbous_5.png'),
451
-
452
- 'moon_last_quarter_path': get_icon_path('last_quarter.png'),
453
-
454
- 'moon_waning_crescent_1_path': get_icon_path('waning_crescent_1.png'),
455
- 'moon_waning_crescent_2_path': get_icon_path('waning_crescent_2.png'),
456
- 'moon_waning_crescent_3_path': get_icon_path('waning_crescent_3.png'),
457
- 'moon_waning_crescent_4_path': get_icon_path('waning_crescent_4.png'),
458
- 'moon_waning_crescent_5_path': get_icon_path('waning_crescent_5.png'),
459
-
460
- 'rgbcombo_path': get_icon_path('rgbcombo.png'),
461
- 'rgbextract_path': get_icon_path('rgbextract.png'),
462
- 'copyslot_path': get_icon_path('copyslot.png'),
463
- 'graxperticon_path': get_icon_path('graxpert.png'),
464
- 'cropicon_path': get_icon_path('cropicon.png'),
465
- 'openfile_path': get_icon_path('openfile.png'),
466
- 'abeicon_path': get_icon_path('abeicon.png'),
467
- 'undoicon_path': get_icon_path('undoicon.png'),
468
- 'redoicon_path': get_icon_path('redoicon.png'),
469
- 'blastericon_path': get_icon_path('blaster.png'),
470
- 'clonestampicon_path': get_icon_path('clonestamp.png'),
471
- 'hdr_path': get_icon_path('hdr.png'),
472
- 'invert_path': get_icon_path('invert.png'),
473
- 'fliphorizontal_path': get_icon_path('fliphorizontal.png'),
474
- 'flipvertical_path': get_icon_path('flipvertical.png'),
475
- 'rotateclockwise_path': get_icon_path('rotateclockwise.png'),
476
- 'rotatecounterclockwise_path': get_icon_path('rotatecounterclockwise.png'),
477
- 'rotate180_path': get_icon_path('rotate180.png'),
478
- 'rotatearbitrary_path': get_icon_path('rotatearbitrary.png'),
479
- 'maskcreate_path': get_icon_path('maskcreate.png'),
480
- 'maskapply_path': get_icon_path('maskapply.png'),
481
- 'maskremove_path': get_icon_path('maskremove.png'),
482
- 'pixelmath_path': get_icon_path('pixelmath.png'),
483
- 'histogram_path': get_icon_path('histogram.png'),
484
- 'mosaic_path': get_icon_path('mosaic.png'),
485
- 'rescale_path': get_icon_path('rescale.png'),
486
- 'staralign_path': get_icon_path('staralign.png'),
487
- 'mask_path': get_icon_path('maskapply.png'),
488
- 'platesolve_path': get_icon_path('platesolve.png'),
489
- 'psf_path': get_icon_path('psf.png'),
490
- 'supernova_path': get_icon_path('supernova.png'),
491
- 'starregistration_path': get_icon_path('starregistration.png'),
492
- 'stacking_path': get_icon_path('stacking.png'),
493
- 'pedestal_icon_path': get_icon_path('pedestal.png'),
494
- 'starspike_path': get_icon_path('starspike.png'),
495
- 'astrospike_path': get_icon_path('Astro_Spikes.png'),
496
- 'aperture_path': get_icon_path('aperture.png'),
497
- 'jwstpupil_path': get_icon_path('jwstpupil.png'),
498
- 'signature_icon_path': get_icon_path('pen.png'),
499
- 'livestacking_path': get_icon_path('livestacking.png'),
500
- 'hrdiagram_path': get_icon_path('HRDiagram.png'),
501
- 'convoicon_path': get_icon_path('convo.png'),
502
- 'spcc_icon_path': get_icon_path('spcc.png'),
503
- 'sasp_data_path': get_data_path('data/SASP_data.fits'),
504
- 'exoicon_path': get_icon_path('exoicon.png'),
505
- 'peeker_icon': get_icon_path('gridicon.png'),
506
- 'dse_icon_path': get_icon_path('dse.png'),
507
- 'astrobin_filters_csv_path': get_data_path('data/catalogs/astrobin_filters.csv'),
508
- 'isophote_path': get_icon_path('isophote.png'),
509
- 'statstretch_path': get_icon_path('statstretch.png'),
510
- 'starstretch_path': get_icon_path('starstretch.png'),
511
- 'curves_path': get_icon_path('curves.png'),
512
- 'disk_path': get_icon_path('disk.png'),
513
- 'uhs_path': get_icon_path('uhs.png'),
514
- 'blink_path': get_icon_path('blink.png'),
515
- 'ppp_path': get_icon_path('ppp.png'),
516
- 'nbtorgb_path': get_icon_path('nbtorgb.png'),
517
- 'freqsep_path': get_icon_path('freqsep.png'),
518
- 'multiscale_decomp_path': get_icon_path('multiscale_decomp.png'),
519
- 'contsub_path': get_icon_path('contsub.png'),
520
- 'halo_path': get_icon_path('halo.png'),
521
- 'cosmic_path': get_icon_path('cosmic.png'),
522
- 'satellite_path': get_icon_path('cosmicsat.png'),
523
- 'imagecombine_path': get_icon_path('imagecombine.png'),
524
- 'wrench_path': get_icon_path('wrench_icon.png'),
525
- 'eye_icon_path': get_icon_path('eye.png'),
526
- 'disk_icon_path': get_icon_path('disk.png'),
527
- 'nuke_path': get_icon_path('nuke.png'),
528
- 'hubble_path': get_icon_path('hubble.png'),
529
- 'collage_path': get_icon_path('collage.png'),
530
- 'annotated_path': get_icon_path('annotated.png'),
531
- 'colorwheel_path': get_icon_path('colorwheel.png'),
532
- 'narrowbandnormalization_path': get_icon_path('narrowbandnormalization.png'),
533
- 'font_path': get_icon_path('font.png'),
534
- 'csv_icon_path': get_icon_path('cvs.png'),
535
- 'spinner_path': get_data_path('spinner.gif'),
536
- 'wims_path': get_icon_path('wims.png'),
537
- 'wimi_path': get_icon_path('wimi_icon_256x256.png'),
538
- 'linearfit_path': get_icon_path('linearfit.png'),
539
- 'debayer_path': get_icon_path('debayer.png'),
540
- 'aberration_path': get_icon_path('aberration.png'),
541
- 'functionbundles_path': get_icon_path('functionbundle.png'),
542
- 'planetarystacker_path': get_icon_path('planetarystacker.png'),
543
- 'viewbundles_path': get_icon_path('viewbundle.png'),
544
- 'selectivecolor_path': get_icon_path('selectivecolor.png'),
545
- 'rgbalign_path': get_icon_path('rgbalign.png'),
546
- 'background_path': get_icon_path('background.png'),
547
- 'script_icon_path': get_icon_path('script.png'),
548
- 'planetprojection_path': get_icon_path('3dplanet.png'),
549
- }
550
572
 
551
573
  class Resources:
552
574
  """
@@ -603,41 +625,37 @@ class Resources:
603
625
 
604
626
  @lru_cache(maxsize=8)
605
627
  def get_models_dir() -> str:
606
- # Prefer user-installed models
607
- try:
608
- from setiastro.saspro.model_manager import models_root
609
- p = Path(models_root())
610
- if p.is_dir():
611
- if any(p.rglob("*.pth")) or any(p.rglob("*.onnx")):
612
- return str(p)
613
- except Exception:
614
- pass
615
-
616
- # Fallback to packaged (dev/frozen) path
617
- return _resource_path('data/models')
628
+ """
629
+ Models are NOT packaged resources. They must be installed via the model manager.
630
+ This returns the user models root and never falls back to _internal/data/models.
631
+ """
632
+ from setiastro.saspro.model_manager import models_root
633
+ p = Path(models_root())
634
+ # Ensure dir exists (models_root should already do this, but harmless)
635
+ p.mkdir(parents=True, exist_ok=True)
636
+ return str(p)
618
637
 
619
- def model_path(filename: str) -> str:
620
- base = Path(get_models_dir())
621
- path = base / filename
622
- return str(path)
623
638
 
624
- # Export all legacy paths as module-level variables
625
- _legacy = _init_legacy_paths()
626
- globals().update(_legacy)
639
+ def _assert_not_internal_models_path(p: str):
640
+ s = str(p).lower().replace("/", "\\")
641
+ if "\\_internal\\" in s and "\\data\\models\\" in s:
642
+ raise RuntimeError(f"Legacy internal model path detected: {p}")
627
643
 
644
+ def model_path(filename: str) -> str:
645
+ from setiastro.saspro.model_manager import require_model
646
+ p = str(require_model(filename))
647
+ _assert_not_internal_models_path(p)
648
+ return p
628
649
 
629
- # Background for startup
630
- background_startup_path = _resource_path('Background_startup.jpg')
631
- _legacy['background_startup_path'] = background_startup_path
632
650
 
633
651
  # QML helper
634
652
  resource_monitor_qml = _resource_path(os.path.join("qml", "ResourceMonitor.qml"))
635
653
 
636
654
  # Export list for `from setiastro.saspro.resources import *`
637
655
  __all__ = [
638
- 'Icons', 'Resources',
656
+ 'Icons', 'Resources',
639
657
  'get_icons', 'get_resources',
640
658
  'get_icon_path', 'get_data_path',
659
+ 'resource_monitor_qml',
641
660
  'background_startup_path',
642
- ] + list(_legacy.keys())
643
-
661
+ ] + list(_LEGACY_ICON_MAP.keys()) + list(_LEGACY_DATA_MAP.keys())