mirror of
https://github.com/migatu/astrololo.git
synced 2026-07-14 13:34:38 +00:00
f6323cac10
Punktacja siły (LOG-21): - scoring.py: siła fasety z sygnałów obliczalnych (typ fasety, rodzaj aspektu, ciasnota orbu). Konfigurowalne wagi. Hook na przyszłość: kolumny countas*/level* z SIGNIFICATORS KEY (obecnie puste). - aspekty niosą orb+allowed; fasety dostają "score"; ranking faset malejąco. Grupowanie: - opcja group: zwija próbki po opisie (ten sam efekt = jedna grupa z listą sygnifikatorów i licznikiem). Checkbox "grupuj identyczne opisy" w /interpret. Geolokalizacja (bajer): - "Tu i teraz" (widok Horoskop i Interpretacje) uzupełnia lat/lon z przeglądarki (navigator.geolocation; wymaga zgody, https/localhost). Zweryfikowano na realnym main_base.xlsx: ranking sensowny (ciasna opozycja z Saturn 9.59 > szeroka koniunkcja z Moon 6.25 > znak/dom 5.0); grupowanie zwija powtórzone opisy. 41 testów przechodzi. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
"""Aspekty — kąty między obiektami (LOG-06, wersja: aspekty główne).
|
|
|
|
Czysta matematyka na policzonych długościach ekliptycznych. Dla każdej pary
|
|
obiektów sprawdzamy, czy ich separacja kątowa mieści się w orbie któregoś z
|
|
aspektów głównych. Applying/separating (aplikacja/separacja) — na później.
|
|
|
|
Tokeny bazy (z SIGNIFICATORS KEY): [conj, [sex, [sq, [tri, [opp.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
MAJOR = {
|
|
"conjunction": 0.0,
|
|
"sextile": 60.0,
|
|
"square": 90.0,
|
|
"trine": 120.0,
|
|
"opposition": 180.0,
|
|
}
|
|
DB_TOKEN = {
|
|
"conjunction": "[conj", "sextile": "[sex", "square": "[sq",
|
|
"trine": "[tri", "opposition": "[opp",
|
|
}
|
|
PL_NAME = {
|
|
"conjunction": "koniunkcja", "sextile": "sekstyl", "square": "kwadratura",
|
|
"trine": "trygon", "opposition": "opozycja",
|
|
}
|
|
LUMINARIES = {"Sun", "Moon"}
|
|
DEFAULT_ORB = 8.0
|
|
LUMINARY_BONUS = 2.0
|
|
|
|
|
|
def separation(a: float, b: float) -> float:
|
|
"""Najmniejsza separacja kątowa [0,180]."""
|
|
d = abs(a - b) % 360.0
|
|
return min(d, 360.0 - d)
|
|
|
|
|
|
def find_aspects(
|
|
positions: list[dict], orb: float = DEFAULT_ORB, luminary_bonus: float = LUMINARY_BONUS
|
|
) -> list[dict]:
|
|
"""positions: dicty z 'name' i 'decimal' (długość). Zwraca listę aspektów."""
|
|
out: list[dict] = []
|
|
n = len(positions)
|
|
for i in range(n):
|
|
for j in range(i + 1, n):
|
|
a, b = positions[i], positions[j]
|
|
la, lb = a.get("decimal"), b.get("decimal")
|
|
if la is None or lb is None:
|
|
continue
|
|
sep = separation(float(la), float(lb))
|
|
allowed = orb + (luminary_bonus if (a["name"] in LUMINARIES or b["name"] in LUMINARIES) else 0.0)
|
|
for asp, angle in MAJOR.items():
|
|
dev = abs(sep - angle)
|
|
if dev <= allowed:
|
|
out.append({
|
|
"obj1": a["name"], "obj2": b["name"],
|
|
"aspect": asp, "orb": round(dev, 2), "allowed": round(allowed, 2),
|
|
})
|
|
break # jedna para = jeden aspekt
|
|
return out
|