f83db2fac1
- add external validation reports and open-source comparison references - integrate Jaimini arudha/graha pada, enhanced argala, and additional synastry kutas - update skill docs and capability matrices - add smoke tests for open-source integrations
149 lines
4.9 KiB
Python
149 lines
4.9 KiB
Python
from .constants import (
|
|
EXALTATION, DEBILITATION, OWN_SIGNS, MOOLTRIKONA,
|
|
SIGN_LORDS, NATURAL_FRIENDS, NATURAL_ENEMIES, NATURAL_NEUTRALS,
|
|
COMBUSTION_ORBS, ZODIAC_SIGNS,
|
|
)
|
|
|
|
|
|
def get_dignity(planet_name, sign, degree_in_sign, planets_in_signs=None):
|
|
"""
|
|
Determine a planet's dignity in a given sign per BPHS.
|
|
Returns one of: exalted, mooltrikona, own_sign, friend, neutral, enemy, debilitated.
|
|
Rahu/Ketu get a simplified check (exalt/debilit/own or neutral).
|
|
"""
|
|
if planet_name in EXALTATION and EXALTATION[planet_name][0] == sign:
|
|
if planet_name in MOOLTRIKONA:
|
|
mt_sign, mt_start, mt_end = MOOLTRIKONA[planet_name]
|
|
if mt_sign == sign and mt_start <= degree_in_sign <= mt_end:
|
|
return "mooltrikona"
|
|
return "exalted"
|
|
|
|
if planet_name in DEBILITATION and DEBILITATION[planet_name][0] == sign:
|
|
return "debilitated"
|
|
|
|
if planet_name in OWN_SIGNS and sign in OWN_SIGNS[planet_name]:
|
|
if planet_name in MOOLTRIKONA:
|
|
mt_sign, mt_start, mt_end = MOOLTRIKONA[planet_name]
|
|
if mt_sign == sign and mt_start <= degree_in_sign <= mt_end:
|
|
return "mooltrikona"
|
|
return "own_sign"
|
|
|
|
if planet_name in MOOLTRIKONA:
|
|
mt_sign, mt_start, mt_end = MOOLTRIKONA[planet_name]
|
|
if mt_sign == sign and mt_start <= degree_in_sign <= mt_end:
|
|
return "mooltrikona"
|
|
|
|
if planet_name in ("Rahu", "Ketu"):
|
|
return "neutral"
|
|
|
|
sign_lord = SIGN_LORDS.get(sign)
|
|
if not sign_lord:
|
|
return "neutral"
|
|
|
|
if planets_in_signs:
|
|
return get_compound_relationship(planet_name, sign, planets_in_signs)
|
|
|
|
if sign_lord in NATURAL_FRIENDS.get(planet_name, []):
|
|
return "friend"
|
|
if sign_lord in NATURAL_ENEMIES.get(planet_name, []):
|
|
return "enemy"
|
|
return "neutral"
|
|
|
|
|
|
def get_compound_relationship(planet_name, sign, planets_in_signs):
|
|
"""
|
|
Compute Panchadha Maitri (5-fold compound relationship).
|
|
Combines natural relationship with temporary friendship.
|
|
Temporary friend = any planet in signs 2,3,4,10,11,12 from the planet.
|
|
Temporary enemy = any planet in signs 1,5,6,7,8,9 (same sign counts as 1).
|
|
|
|
Parameters
|
|
----------
|
|
planet_name : str
|
|
sign : str - the sign the planet occupies
|
|
planets_in_signs : dict - {planet_name: sign_index} for all planets
|
|
|
|
Returns one of: great_friend, friend, neutral, enemy, great_enemy
|
|
"""
|
|
sign_lord = SIGN_LORDS.get(sign)
|
|
if not sign_lord or planet_name in ("Rahu", "Ketu"):
|
|
return "neutral"
|
|
|
|
natural = _natural_relationship(planet_name, sign_lord)
|
|
|
|
planet_sign_idx = ZODIAC_SIGNS.index(sign)
|
|
sign_lord_idx = None
|
|
for p, idx in planets_in_signs.items():
|
|
if p == sign_lord:
|
|
sign_lord_idx = idx
|
|
break
|
|
if sign_lord_idx is None:
|
|
return natural
|
|
|
|
dist = (sign_lord_idx - planet_sign_idx) % 12
|
|
# Houses 2,3,4,10,11,12 from planet are temporary friends (BPHS)
|
|
# dist values {1,2,3,9,10,11} map to these houses (0-indexed)
|
|
temp_friend_positions = {1, 2, 3, 9, 10, 11}
|
|
is_temp_friend = dist in temp_friend_positions
|
|
|
|
compound = _combine_relationships(natural, is_temp_friend)
|
|
return compound
|
|
|
|
|
|
def _natural_relationship(planet, other):
|
|
if other in NATURAL_FRIENDS.get(planet, []):
|
|
return "friend"
|
|
if other in NATURAL_ENEMIES.get(planet, []):
|
|
return "enemy"
|
|
return "neutral"
|
|
|
|
|
|
def _combine_relationships(natural, is_temp_friend):
|
|
"""Panchadha Maitri combination table."""
|
|
if natural == "friend" and is_temp_friend:
|
|
return "great_friend"
|
|
if natural == "friend" and not is_temp_friend:
|
|
return "neutral"
|
|
if natural == "neutral" and is_temp_friend:
|
|
return "friend"
|
|
if natural == "neutral" and not is_temp_friend:
|
|
return "enemy"
|
|
if natural == "enemy" and is_temp_friend:
|
|
return "neutral"
|
|
if natural == "enemy" and not is_temp_friend:
|
|
return "great_enemy"
|
|
return "neutral"
|
|
|
|
|
|
def check_combustion(planet_name, planet_lon, sun_lon, is_retrograde=False):
|
|
"""
|
|
Check if a planet is combust (too close to the Sun).
|
|
Sun, Rahu, Ketu cannot be combust.
|
|
"""
|
|
if planet_name in ("Sun", "Rahu", "Ketu"):
|
|
return False
|
|
|
|
orb_data = COMBUSTION_ORBS.get(planet_name)
|
|
if orb_data is None:
|
|
return False
|
|
|
|
if isinstance(orb_data, dict):
|
|
orb = orb_data["retrograde"] if is_retrograde else orb_data["direct"]
|
|
else:
|
|
orb = orb_data
|
|
|
|
angular_dist = abs(planet_lon - sun_lon)
|
|
if angular_dist > 180:
|
|
angular_dist = 360 - angular_dist
|
|
|
|
return angular_dist <= orb
|
|
|
|
|
|
def get_digbala(planet_name, house):
|
|
"""Check if a planet has directional strength in its current house."""
|
|
from .constants import DIGBALA_HOUSES
|
|
ideal_house = DIGBALA_HOUSES.get(planet_name)
|
|
if ideal_house is None:
|
|
return False
|
|
return house == ideal_house
|