Lots / punkty arabskie — 7 Lots hermetycznych (LOG-08)
- 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>
This commit is contained in:
@@ -24,6 +24,8 @@ ABBREVIATIONS: dict[str, str] = {
|
||||
"NN": "North Node", "SN": "South Node", "Lilith": "Lilith", "Chiron": "Chiron",
|
||||
# osie
|
||||
"Asc": "Ascendant", "Dsc": "Descendant", "MC": "Midheaven", "IC": "Imum Coeli",
|
||||
# Lots (punkty arabskie)
|
||||
"PF": "Part of Fortune", "Fortune": "Part of Fortune", "Spirit": "Lot of Spirit",
|
||||
# aspekty
|
||||
"conj": "conjunction", "sex": "sextile", "sq": "square", "tri": "trine",
|
||||
"opp": "opposition", "semisex": "semisextile", "semisq": "semisquare",
|
||||
|
||||
@@ -21,7 +21,8 @@ def _fmt(name: str, lon: float) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def build_chart(engine: EphemerisEngine, moment: ChartMoment, house_system: str = H.WHOLE_SIGN) -> dict:
|
||||
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)
|
||||
@@ -50,4 +51,20 @@ def build_chart(engine: EphemerisEngine, moment: ChartMoment, house_system: str
|
||||
]
|
||||
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
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Lots / punkty arabskie (LOG-08) — 7 Lots hermetycznych.
|
||||
|
||||
Formuła: Lot = C + A − B (od punktu C odmierzamy odległość między A i B).
|
||||
Większość Lots **odwraca się w horoskopach nocnych** (zamiana A↔B) — np.
|
||||
Fortuna: dzień Asc + Mo − Su, noc Asc + Su − Mo.
|
||||
|
||||
Dwa warianty liczenia (notes3):
|
||||
- `degree` (domyślny) — dokładny stopień,
|
||||
- `sign` — liczone całymi znakami (Lot wypada na 0° wyliczonego znaku).
|
||||
|
||||
Kolejność ma znaczenie: Fortuna i Duch liczone są pierwsze, bo pozostałe Lots
|
||||
odwołują się do nich.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from app.engine.formats import norm360, sign_index
|
||||
|
||||
# (nazwa, C, A, B, odwracalny w nocy)
|
||||
LOT_DEFS: list[tuple[str, str, str, str, bool]] = [
|
||||
("Fortune", "Asc", "Moon", "Sun", True),
|
||||
("Spirit", "Asc", "Sun", "Moon", True),
|
||||
("Eros", "Asc", "Venus", "Spirit", True),
|
||||
("Necessity", "Asc", "Fortune", "Mercury", True),
|
||||
("Courage", "Asc", "Fortune", "Mars", True),
|
||||
("Victory", "Asc", "Jupiter", "Spirit", True),
|
||||
("Nemesis", "Asc", "Fortune", "Saturn", True),
|
||||
]
|
||||
|
||||
METHODS = ("degree", "sign")
|
||||
|
||||
|
||||
def compute_lots(
|
||||
points: dict[str, float], is_day: bool, method: str = "degree"
|
||||
) -> list[dict]:
|
||||
"""points: nazwa → długość natalna (wymagane Asc + planety formuł).
|
||||
|
||||
Zwraca listę {name, longitude, formula} w kolejności definicji.
|
||||
"""
|
||||
if method not in METHODS:
|
||||
raise ValueError(f"nieznana metoda liczenia Lots: {method}")
|
||||
|
||||
vals = dict(points)
|
||||
out: list[dict] = []
|
||||
for name, c, a, b, reversible in LOT_DEFS:
|
||||
first, second = (a, b) if (is_day or not reversible) else (b, a)
|
||||
if any(k not in vals for k in (c, first, second)):
|
||||
continue # brak składnika — pomijamy
|
||||
if method == "sign":
|
||||
idx = (sign_index(vals[c]) + sign_index(vals[first])
|
||||
- sign_index(vals[second])) % 12
|
||||
lon = idx * 30.0
|
||||
else:
|
||||
lon = norm360(vals[c] + vals[first] - vals[second])
|
||||
vals[name] = lon # dostępny dla kolejnych Lots
|
||||
out.append({
|
||||
"name": name,
|
||||
"longitude": lon,
|
||||
"formula": f"{c} + {first} − {second}",
|
||||
})
|
||||
return out
|
||||
@@ -22,6 +22,8 @@ PLANET_ABBR = {
|
||||
"Jupiter": "Ju", "Saturn": "Sa", "Uranus": "Ur", "Neptune": "Ne", "Pluto": "Pl",
|
||||
# punkty wirtualne — tokeny wg SIGNIFICATORS KEY ([NN, [SN, [Lilith)
|
||||
"North Node": "NN", "South Node": "SN", "Lilith": "Lilith",
|
||||
# Lots — w bazie Fortuna występuje jako [PF (Part of Fortune)
|
||||
"Fortune": "PF", "Spirit": "Spirit",
|
||||
}
|
||||
SIGN_TO_ABBR = dict(zip(SIGNS, SIGN_ABBR))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user