mirror of
https://github.com/migatu/astrololo.git
synced 2026-07-14 21:38:37 +00:00
94c3023d3a
Kontynuacja silnika efemeryd o osie i domy. - engine/houses.py: czysta matematyka sferyczna — Asc, MC (z RAMC + ε + φ), cusps dla Whole Sign / Equal / Porphyry, przypisanie obiektu do domu. - SkyfieldEngine.sidereal(): RAMC (lokalny apparent ST) + średnie nachylenie ekliptyki ze Skyfielda. - engine/chart.py: build_chart() składa pełny horoskop (pozycje + osie + domy). - Endpoint /chart/positions rozszerzony o house_system i zwraca angles + cusps + numer domu per obiekt. - Prezentacja: lokalizacja i wybór systemu domów w formularzu, tabela osi, kolumna Dom, rozwijane cusps. Walidacja względem astro.com (30.04.1984, Warszawa): Asc Can 22°10'43", MC Pis 22°35'29" (~1' od referencji); wszystkie przypisania domów Whole Sign zgodne (Sun 11, Mercury 10, Mars 5, ...). 20 testów przechodzi. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
"""Osie i domy — czysta matematyka sferyczna (LOG-05).
|
|
|
|
Bezstanowe funkcje: z lokalnego czasu gwiazdowego (RAMC), nachylenia ekliptyki
|
|
(ε) i szerokości geograficznej (φ) wyliczają Ascendent i MC, a stąd cusps domów
|
|
dla prostych systemów (Whole Sign, Equal, Porphyry). Niezależne od silnika —
|
|
silnik dostarcza tylko RAMC i ε.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
from app.engine.formats import SIGN_ABBR, norm360, sign_index # noqa: F401
|
|
|
|
WHOLE_SIGN = "whole_sign"
|
|
EQUAL = "equal"
|
|
PORPHYRY = "porphyry"
|
|
SYSTEMS = (WHOLE_SIGN, EQUAL, PORPHYRY)
|
|
|
|
|
|
def mean_obliquity(tt_jd: float) -> float:
|
|
"""Średnie nachylenie ekliptyki [°] dla daty (Julian TT). Wystarcza do domów."""
|
|
t = (tt_jd - 2451545.0) / 36525.0
|
|
arcsec = 84381.448 - 46.8150 * t - 0.00059 * t * t + 0.001813 * t ** 3
|
|
return arcsec / 3600.0
|
|
|
|
|
|
def compute_mc(ramc_deg: float, eps_deg: float) -> float:
|
|
r, e = math.radians(ramc_deg), math.radians(eps_deg)
|
|
mc = math.atan2(math.sin(r), math.cos(r) * math.cos(e))
|
|
return norm360(math.degrees(mc))
|
|
|
|
|
|
def compute_asc(ramc_deg: float, eps_deg: float, lat_deg: float) -> float:
|
|
r, e, phi = math.radians(ramc_deg), math.radians(eps_deg), math.radians(lat_deg)
|
|
asc = math.atan2(
|
|
math.cos(r),
|
|
-(math.sin(r) * math.cos(e) + math.tan(phi) * math.sin(e)),
|
|
)
|
|
return norm360(math.degrees(asc))
|
|
|
|
|
|
def _trisect(a: float, b: float) -> tuple[float, float]:
|
|
"""Dwa punkty dzielące łuk a→b (w kierunku zodiaku) na trzy równe części."""
|
|
span = (b - a) % 360.0
|
|
return norm360(a + span / 3.0), norm360(a + 2.0 * span / 3.0)
|
|
|
|
|
|
def cusps(asc: float, mc: float, system: str) -> list[float]:
|
|
"""Zwraca 12 cusps (długości) domów 1..12."""
|
|
if system == WHOLE_SIGN:
|
|
start = sign_index(asc) * 30.0
|
|
return [norm360(start + 30.0 * i) for i in range(12)]
|
|
if system == EQUAL:
|
|
return [norm360(asc + 30.0 * i) for i in range(12)]
|
|
if system == PORPHYRY:
|
|
dsc, ic = norm360(asc + 180.0), norm360(mc + 180.0)
|
|
c = [0.0] * 12
|
|
c[0], c[3], c[6], c[9] = asc, ic, dsc, mc
|
|
c[1], c[2] = _trisect(asc, ic) # domy 2,3
|
|
c[4], c[5] = _trisect(ic, dsc) # domy 5,6
|
|
c[7], c[8] = _trisect(dsc, mc) # domy 8,9
|
|
c[10], c[11] = _trisect(mc, asc) # domy 11,12
|
|
return c
|
|
raise ValueError(f"nieznany system domów: {system}")
|
|
|
|
|
|
def assign_house(lon: float, cusp_list: list[float]) -> int:
|
|
"""Numer domu (1..12), w którym leży dana długość ekliptyczna."""
|
|
lon = norm360(lon)
|
|
for i in range(12):
|
|
start = cusp_list[i]
|
|
end = cusp_list[(i + 1) % 12]
|
|
span = (end - start) % 360.0
|
|
offset = (lon - start) % 360.0
|
|
if offset < span:
|
|
return i + 1
|
|
return 12
|