mirror of
https://github.com/migatu/astrololo.git
synced 2026-07-14 21:38:37 +00:00
166b438f83
Aspekty: - engine/aspects.py: aspekty główne (conj/sex/sq/tri/opp) z orbami (bonus dla luminarzy), separacja z obsługą zawinięcia. Applying/sep na później. - build_chart zwraca listę aspektów; /chart/positions je udostępnia; widok Horoskop pokazuje tabelę aspektów. Bogatsze sygnifikatory: - trzecia faseta "w aspekcie": dla każdego aspektu głównego obiektu filtruje rekordy po tokenie aspektu + drugiej planety ([conj + [Mo). Cookbook komplet: znak + dom + aspekt. Dopieszczenie wyników: - ODSIEWANIE DUPLIKATÓW: duplikat = ten sam sygnifikator ORAZ ten sam opis (po normalizacji). Dedup wewnątrz fasety, działa też na wynikach z wielu baz. - _facet_samples przyjmuje wiele tokenów (AND); dedup + istniejące odsiewanie szumu. Zweryfikowano na realnym main_base.xlsx (30.04.1984): 16 aspektów zgodnych z astro.com (Sun conj Moon 9.59°, Sun opp Saturn 3.17°); faseta aspektu daje bogate trafienia (Sun koniunkcja z Moon 84, opozycja z Saturn 43); dedup obniżył duplikaty (Sun w znaku 46->44). 36 testów przechodzi. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
1.8 KiB
Python
54 lines
1.8 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) -> 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)
|
|
return result
|