79bce8ae90
- engine/lots.py: formuła Lot = C + A − B z odwracaniem w horoskopach nocnych (zamiana A<->B); 7 Lots hermetycznych (Fortuna, Duch, Eros, Konieczność, Odwaga, Zwycięstwo, Nemezis) — Fortuna i Duch liczone pierwsze, bo pozostałe się do nich odwołują. Dwa warianty: degree (domyślny) i sign (całe znaki). - build_chart: liczy sektę (reużyta is_day_birth z Firdarii) i zwraca lots ze znakiem, pozycją i domem; parametr lots_method. - wyszukiwarka: token [PF (tak Fortuna występuje w realnej bazie) + rozwinięcie skrótu do "Part of Fortune". - widok Horoskop: tabela Lots z formułami i sektą. Walidacja (dwie niezależne wyrocznie z notes3): - Fortuna = Can 12°35'27" vs astro-seek Can 12°35'24" (3 sekundy różnicy), dom 1; - Duch potwierdzony przez swoją antyscję (Taurus 28°14' z tabeli antyscji); - odwracanie nocne: Fortuna nocna == Duch dzienny i odwrotnie; - Lots pochodne faktycznie używają Fortuny/Ducha; wariant sign trafia w 0° znaku. 85 testów przechodzi (nowy test_lots). Odblokowuje Zodiacal Releasing (LOG-11), które startuje z Fortuny/Ducha. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
"""Złożenie pełnego horoskopu: pozycje + osie + domy (LOG-01 + LOG-05).
|
|
|
|
Silnik-agnostyczne: potrzebuje tylko `positions()` oraz (dla osi/domów)
|
|
`sidereal()`. Jeśli silnik nie umie policzyć czasu gwiazdowego, zwraca same
|
|
pozycje.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from app.engine import houses as H
|
|
from app.engine.base import EphemerisEngine
|
|
from app.engine.formats import SIGNS, in_sign, norm360, sign_index
|
|
from app.engine.models import ChartMoment
|
|
|
|
|
|
def _fmt(name: str, lon: float) -> dict:
|
|
return {
|
|
"name": name,
|
|
"sign": SIGNS[sign_index(lon)],
|
|
"in_sign": in_sign(lon),
|
|
"decimal": round(norm360(lon), 6),
|
|
}
|
|
|
|
|
|
def build_chart(engine: EphemerisEngine, moment: ChartMoment, house_system: str = H.WHOLE_SIGN,
|
|
lots_method: str = "degree") -> dict:
|
|
from app.engine.aspects import find_aspects
|
|
|
|
positions = engine.positions(moment)
|
|
result: dict = {"engine": engine.name, "positions": [p.as_dict() for p in positions]}
|
|
result["aspects"] = find_aspects(result["positions"]) # aspekty (LOG-06)
|
|
|
|
if not hasattr(engine, "sidereal"):
|
|
return result
|
|
|
|
ramc, eps = engine.sidereal(moment)
|
|
asc = H.compute_asc(ramc, eps, moment.lat)
|
|
mc = H.compute_mc(ramc, eps)
|
|
system = house_system if house_system in H.SYSTEMS else H.WHOLE_SIGN
|
|
cusp_list = H.cusps(asc, mc, system)
|
|
|
|
result["house_system"] = system
|
|
result["angles"] = {
|
|
"Asc": _fmt("Asc", asc),
|
|
"MC": _fmt("MC", mc),
|
|
"Dsc": _fmt("Dsc", norm360(asc + 180.0)),
|
|
"IC": _fmt("IC", norm360(mc + 180.0)),
|
|
}
|
|
result["cusps"] = [
|
|
{"house": i + 1, "sign": SIGNS[sign_index(c)], "in_sign": in_sign(c)}
|
|
for i, c in enumerate(cusp_list)
|
|
]
|
|
for pdict, obj in zip(result["positions"], positions):
|
|
pdict["house"] = H.assign_house(obj.longitude, cusp_list)
|
|
|
|
# Lots (LOG-08) — wymagają Asc i sekty (dzień/noc)
|
|
from app.engine.firdaria import is_day_birth
|
|
from app.engine.lots import compute_lots
|
|
|
|
pts = {p.name: p.longitude for p in positions}
|
|
pts["Asc"] = asc
|
|
day = is_day_birth(pts["Sun"], asc, mc) if "Sun" in pts else True
|
|
result["sect"] = "day" if day else "night"
|
|
result["lots"] = [
|
|
{**lot,
|
|
"sign": SIGNS[sign_index(lot["longitude"])],
|
|
"in_sign": in_sign(lot["longitude"]),
|
|
"house": H.assign_house(lot["longitude"], cusp_list)}
|
|
for lot in compute_lots(pts, day, lots_method)
|
|
]
|
|
return result
|