kundali-chart-mcp 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/azure-function/function_app.py +93 -0
- package/azure-function/host.json +15 -0
- package/azure-function/kundali_bridge.py +952 -0
- package/azure-function/python/kundali_lib/__init__.py +1 -0
- package/azure-function/python/kundali_lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/ephemeris.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/geocoder.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/vedicastro_bridge.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/ephemeris.py +30 -0
- package/azure-function/python/kundali_lib/geocoder.py +82 -0
- package/azure-function/python/kundali_lib/vedic/__init__.py +1 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/arishta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/ashtakavarga.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/avasthas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/ayanamsa.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/bhava_chalit.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/char_dasha.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/chart.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/chart_types.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/compatibility.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/constants.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/dasha_extended.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/dasha_systems.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/doshas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/gandanta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/gochara.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/hora.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/houses.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/jaimini.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kalachakra.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kartari.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kurmachakra.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/lunar_return.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/muhurta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/nabhasha.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/nakshatra_details.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/panchanga.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/planets.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/shadbala.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/special_conditions.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/sudarshana.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/tajaka.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/upagrahas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/varshaphal.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/yogas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/zodiac.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/arishta.py +465 -0
- package/azure-function/python/kundali_lib/vedic/ashtakavarga.py +213 -0
- package/azure-function/python/kundali_lib/vedic/avasthas.py +292 -0
- package/azure-function/python/kundali_lib/vedic/ayanamsa.py +106 -0
- package/azure-function/python/kundali_lib/vedic/bhava_chalit.py +137 -0
- package/azure-function/python/kundali_lib/vedic/char_dasha.py +308 -0
- package/azure-function/python/kundali_lib/vedic/chart.py +126 -0
- package/azure-function/python/kundali_lib/vedic/chart_types.py +338 -0
- package/azure-function/python/kundali_lib/vedic/compatibility.py +705 -0
- package/azure-function/python/kundali_lib/vedic/constants.py +108 -0
- package/azure-function/python/kundali_lib/vedic/dasha_extended.py +262 -0
- package/azure-function/python/kundali_lib/vedic/dasha_systems.py +439 -0
- package/azure-function/python/kundali_lib/vedic/doshas.py +453 -0
- package/azure-function/python/kundali_lib/vedic/gandanta.py +213 -0
- package/azure-function/python/kundali_lib/vedic/gochara.py +277 -0
- package/azure-function/python/kundali_lib/vedic/hora.py +263 -0
- package/azure-function/python/kundali_lib/vedic/houses.py +30 -0
- package/azure-function/python/kundali_lib/vedic/jaimini.py +361 -0
- package/azure-function/python/kundali_lib/vedic/kalachakra.py +226 -0
- package/azure-function/python/kundali_lib/vedic/kartari.py +243 -0
- package/azure-function/python/kundali_lib/vedic/kurmachakra.py +383 -0
- package/azure-function/python/kundali_lib/vedic/lunar_return.py +402 -0
- package/azure-function/python/kundali_lib/vedic/muhurta.py +414 -0
- package/azure-function/python/kundali_lib/vedic/nabhasha.py +349 -0
- package/azure-function/python/kundali_lib/vedic/nakshatra_details.py +945 -0
- package/azure-function/python/kundali_lib/vedic/panchanga.py +297 -0
- package/azure-function/python/kundali_lib/vedic/planets.py +55 -0
- package/azure-function/python/kundali_lib/vedic/shadbala.py +500 -0
- package/azure-function/python/kundali_lib/vedic/special_conditions.py +319 -0
- package/azure-function/python/kundali_lib/vedic/sudarshana.py +232 -0
- package/azure-function/python/kundali_lib/vedic/tajaka.py +482 -0
- package/azure-function/python/kundali_lib/vedic/upagrahas.py +229 -0
- package/azure-function/python/kundali_lib/vedic/varshaphal.py +185 -0
- package/azure-function/python/kundali_lib/vedic/yogas.py +935 -0
- package/azure-function/python/kundali_lib/vedic/zodiac.py +42 -0
- package/azure-function/python/kundali_lib/vedicastro_bridge.py +198 -0
- package/azure-function/requirements.txt +9 -0
- package/index.js +747 -0
- package/kundali-chart-mcp.js +159 -0
- package/kundali_bridge.py +952 -0
- package/package.json +41 -0
- package/python/kundali_lib/__init__.py +1 -0
- package/python/kundali_lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/ephemeris.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/geocoder.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/vedicastro_bridge.cpython-313.pyc +0 -0
- package/python/kundali_lib/ephemeris.py +30 -0
- package/python/kundali_lib/geocoder.py +82 -0
- package/python/kundali_lib/vedic/__init__.py +1 -0
- package/python/kundali_lib/vedic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/arishta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/ashtakavarga.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/avasthas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/ayanamsa.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/bhava_chalit.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/char_dasha.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/chart.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/chart_types.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/compatibility.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/constants.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/dasha_extended.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/dasha_systems.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/doshas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/gandanta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/gochara.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/hora.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/houses.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/jaimini.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kalachakra.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kartari.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kurmachakra.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/lunar_return.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/muhurta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/nabhasha.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/nakshatra_details.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/panchanga.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/planets.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/shadbala.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/special_conditions.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/sudarshana.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/tajaka.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/upagrahas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/varshaphal.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/yogas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/zodiac.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/arishta.py +465 -0
- package/python/kundali_lib/vedic/ashtakavarga.py +213 -0
- package/python/kundali_lib/vedic/avasthas.py +292 -0
- package/python/kundali_lib/vedic/ayanamsa.py +106 -0
- package/python/kundali_lib/vedic/bhava_chalit.py +137 -0
- package/python/kundali_lib/vedic/char_dasha.py +308 -0
- package/python/kundali_lib/vedic/chart.py +126 -0
- package/python/kundali_lib/vedic/chart_types.py +338 -0
- package/python/kundali_lib/vedic/compatibility.py +705 -0
- package/python/kundali_lib/vedic/constants.py +108 -0
- package/python/kundali_lib/vedic/dasha_extended.py +262 -0
- package/python/kundali_lib/vedic/dasha_systems.py +439 -0
- package/python/kundali_lib/vedic/doshas.py +453 -0
- package/python/kundali_lib/vedic/gandanta.py +213 -0
- package/python/kundali_lib/vedic/gochara.py +277 -0
- package/python/kundali_lib/vedic/hora.py +263 -0
- package/python/kundali_lib/vedic/houses.py +30 -0
- package/python/kundali_lib/vedic/jaimini.py +361 -0
- package/python/kundali_lib/vedic/kalachakra.py +226 -0
- package/python/kundali_lib/vedic/kartari.py +243 -0
- package/python/kundali_lib/vedic/kurmachakra.py +383 -0
- package/python/kundali_lib/vedic/lunar_return.py +402 -0
- package/python/kundali_lib/vedic/muhurta.py +414 -0
- package/python/kundali_lib/vedic/nabhasha.py +349 -0
- package/python/kundali_lib/vedic/nakshatra_details.py +945 -0
- package/python/kundali_lib/vedic/panchanga.py +297 -0
- package/python/kundali_lib/vedic/planets.py +55 -0
- package/python/kundali_lib/vedic/shadbala.py +500 -0
- package/python/kundali_lib/vedic/special_conditions.py +319 -0
- package/python/kundali_lib/vedic/sudarshana.py +232 -0
- package/python/kundali_lib/vedic/tajaka.py +482 -0
- package/python/kundali_lib/vedic/upagrahas.py +229 -0
- package/python/kundali_lib/vedic/varshaphal.py +185 -0
- package/python/kundali_lib/vedic/yogas.py +935 -0
- package/python/kundali_lib/vedic/zodiac.py +42 -0
- package/python/kundali_lib/vedicastro_bridge.py +198 -0
- package/remote-server.js +590 -0
- package/requirements.txt +8 -0
- package/setup.sh +218 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""Planetary Avasthas: 9 states of planets in a birth chart."""
|
|
2
|
+
|
|
3
|
+
# ---------------------------------------------------------------------------
|
|
4
|
+
# Avastha reference data
|
|
5
|
+
# ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
AVASTHAS = {
|
|
8
|
+
"Deepta": {
|
|
9
|
+
"condition": "Exaltation sign",
|
|
10
|
+
"strength": 1.0,
|
|
11
|
+
"nature": "Highly auspicious",
|
|
12
|
+
},
|
|
13
|
+
"Swastha": {
|
|
14
|
+
"condition": "Own sign (including Moolatrikona)",
|
|
15
|
+
"strength": 0.875,
|
|
16
|
+
"nature": "Auspicious",
|
|
17
|
+
},
|
|
18
|
+
"Mudita": {"condition": "Friend's sign", "strength": 0.75, "nature": "Pleasing"},
|
|
19
|
+
"Santha": {"condition": "Neutral sign", "strength": 0.5, "nature": "Neutral"},
|
|
20
|
+
"Dina": {"condition": "Enemy's sign", "strength": 0.375, "nature": "Distressed"},
|
|
21
|
+
"Dukhita": {
|
|
22
|
+
"condition": "Combust (within combustion threshold of Sun)",
|
|
23
|
+
"strength": 0.25,
|
|
24
|
+
"nature": "Pained",
|
|
25
|
+
},
|
|
26
|
+
"Vikala": {
|
|
27
|
+
"condition": "Defeated in Graha Yuddha (within 1° of another planet)",
|
|
28
|
+
"strength": 0.125,
|
|
29
|
+
"nature": "Crippled",
|
|
30
|
+
},
|
|
31
|
+
"Khala": {
|
|
32
|
+
"condition": "Debilitation sign",
|
|
33
|
+
"strength": 0.0,
|
|
34
|
+
"nature": "Wicked/Weak",
|
|
35
|
+
},
|
|
36
|
+
"Bhadra": {
|
|
37
|
+
"condition": "Retrograde in exaltation or own sign",
|
|
38
|
+
"strength": 1.0,
|
|
39
|
+
"nature": "Fortunate (exception)",
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
EXALTATION_SIGNS = {
|
|
44
|
+
"Sun": "Aries",
|
|
45
|
+
"Moon": "Taurus",
|
|
46
|
+
"Mars": "Capricorn",
|
|
47
|
+
"Mercury": "Virgo",
|
|
48
|
+
"Jupiter": "Cancer",
|
|
49
|
+
"Venus": "Pisces",
|
|
50
|
+
"Saturn": "Libra",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
DEBILITATION_SIGNS = {
|
|
54
|
+
"Sun": "Libra",
|
|
55
|
+
"Moon": "Scorpio",
|
|
56
|
+
"Mars": "Cancer",
|
|
57
|
+
"Mercury": "Pisces",
|
|
58
|
+
"Jupiter": "Capricorn",
|
|
59
|
+
"Venus": "Virgo",
|
|
60
|
+
"Saturn": "Aries",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
OWN_SIGNS = {
|
|
64
|
+
"Sun": ["Leo"],
|
|
65
|
+
"Moon": ["Cancer"],
|
|
66
|
+
"Mars": ["Aries", "Scorpio"],
|
|
67
|
+
"Mercury": ["Gemini", "Virgo"],
|
|
68
|
+
"Jupiter": ["Sagittarius", "Pisces"],
|
|
69
|
+
"Venus": ["Taurus", "Libra"],
|
|
70
|
+
"Saturn": ["Capricorn", "Aquarius"],
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
MOOLATRIKONA = {
|
|
74
|
+
"Sun": "Leo",
|
|
75
|
+
"Moon": "Taurus",
|
|
76
|
+
"Mars": "Aries",
|
|
77
|
+
"Mercury": "Virgo",
|
|
78
|
+
"Jupiter": "Sagittarius",
|
|
79
|
+
"Venus": "Libra",
|
|
80
|
+
"Saturn": "Aquarius",
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Degrees within which a planet is considered combust by the Sun
|
|
84
|
+
COMBUSTION_DEG = {
|
|
85
|
+
"Moon": 12,
|
|
86
|
+
"Mars": 17,
|
|
87
|
+
"Mercury": 14,
|
|
88
|
+
"Jupiter": 11,
|
|
89
|
+
"Venus": 10,
|
|
90
|
+
"Saturn": 15,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
PLANET_FRIENDS = {
|
|
94
|
+
"Sun": ["Moon", "Mars", "Jupiter"],
|
|
95
|
+
"Moon": ["Sun", "Mercury"],
|
|
96
|
+
"Mars": ["Sun", "Moon", "Jupiter"],
|
|
97
|
+
"Mercury": ["Sun", "Venus"],
|
|
98
|
+
"Jupiter": ["Sun", "Moon", "Mars"],
|
|
99
|
+
"Venus": ["Mercury", "Saturn"],
|
|
100
|
+
"Saturn": ["Mercury", "Venus"],
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
PLANET_ENEMIES = {
|
|
104
|
+
"Sun": ["Venus", "Saturn"],
|
|
105
|
+
"Moon": [],
|
|
106
|
+
"Mars": ["Mercury"],
|
|
107
|
+
"Mercury": ["Moon"],
|
|
108
|
+
"Jupiter": ["Mercury", "Venus"],
|
|
109
|
+
"Venus": ["Sun", "Moon"],
|
|
110
|
+
"Saturn": ["Sun", "Moon", "Mars"],
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Planets for which we compute Avasthas (the 7 classical planets)
|
|
114
|
+
_CLASSICAL_PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
|
115
|
+
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
# Baladi Avastha (age-based state by degree within sign)
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
_BALADI_THRESHOLDS = [
|
|
121
|
+
(6, "Bala", 0.25), # Infant 0–6°
|
|
122
|
+
(12, "Kumara", 0.50), # Young 6–12°
|
|
123
|
+
(18, "Yuva", 1.00), # Youth 12–18° (peak)
|
|
124
|
+
(24, "Vriddha", 0.50), # Old 18–24°
|
|
125
|
+
(30, "Mrita", 0.25), # Dead 24–30°
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _get_baladi(degree_in_sign: float) -> tuple:
|
|
130
|
+
"""Return (baladi_name, baladi_strength) for a degree within a sign (0–30)."""
|
|
131
|
+
for upper, name, strength in _BALADI_THRESHOLDS:
|
|
132
|
+
if degree_in_sign < upper:
|
|
133
|
+
return name, strength
|
|
134
|
+
return "Mrita", 0.25 # fallback for exactly 30°
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _angular_diff(lon1: float, lon2: float) -> float:
|
|
138
|
+
"""Shortest angular distance between two longitudes (0–180)."""
|
|
139
|
+
diff = abs(lon1 - lon2) % 360
|
|
140
|
+
return diff if diff <= 180 else 360 - diff
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# ---------------------------------------------------------------------------
|
|
144
|
+
# Main function
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def get_avasthas(planetary_positions: list, ascendant: dict) -> list:
|
|
149
|
+
"""Compute the Avastha (planetary state) for each classical planet.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
planetary_positions : list
|
|
154
|
+
Each item is a dict with at least:
|
|
155
|
+
``name``, ``longitude``, ``rashi``, ``degree`` (= degree within sign),
|
|
156
|
+
``house``, ``is_retrograde``.
|
|
157
|
+
ascendant : dict
|
|
158
|
+
Must contain at least ``longitude`` and ``rashi``.
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
list of dict
|
|
163
|
+
One entry per classical planet (Sun–Saturn) found in
|
|
164
|
+
*planetary_positions*, each with keys:
|
|
165
|
+
planet, rashi, house, avastha, strength_ratio, nature,
|
|
166
|
+
condition_met, is_retrograde, baladi_avastha, baladi_strength.
|
|
167
|
+
"""
|
|
168
|
+
# Build quick lookup by name
|
|
169
|
+
planet_map = {p["name"]: p for p in planetary_positions}
|
|
170
|
+
|
|
171
|
+
sun = planet_map.get("Sun")
|
|
172
|
+
sun_lon = sun["longitude"] if sun else None
|
|
173
|
+
|
|
174
|
+
results = []
|
|
175
|
+
|
|
176
|
+
for name in _CLASSICAL_PLANETS:
|
|
177
|
+
p = planet_map.get(name)
|
|
178
|
+
if p is None:
|
|
179
|
+
continue
|
|
180
|
+
|
|
181
|
+
rashi = p["rashi"]
|
|
182
|
+
lon = p["longitude"]
|
|
183
|
+
house = p["house"]
|
|
184
|
+
is_retro = p.get("is_retrograde", False)
|
|
185
|
+
# degree_in_sign: prefer "degree" key, else compute from longitude
|
|
186
|
+
deg_in_sign = p.get("degree", lon % 30)
|
|
187
|
+
|
|
188
|
+
# ------------------------------------------------------------------
|
|
189
|
+
# Determine Avastha (priority order)
|
|
190
|
+
# ------------------------------------------------------------------
|
|
191
|
+
avastha = None
|
|
192
|
+
condition_met = ""
|
|
193
|
+
|
|
194
|
+
# 1. Bhadra: retrograde AND (exaltation OR own sign)
|
|
195
|
+
if is_retro and (
|
|
196
|
+
EXALTATION_SIGNS.get(name) == rashi
|
|
197
|
+
or rashi in OWN_SIGNS.get(name, [])
|
|
198
|
+
or MOOLATRIKONA.get(name) == rashi
|
|
199
|
+
):
|
|
200
|
+
avastha = "Bhadra"
|
|
201
|
+
condition_met = "Retrograde in exaltation/own sign"
|
|
202
|
+
|
|
203
|
+
# 2. Deepta: exaltation sign
|
|
204
|
+
elif EXALTATION_SIGNS.get(name) == rashi:
|
|
205
|
+
avastha = "Deepta"
|
|
206
|
+
condition_met = f"Exalted in {rashi}"
|
|
207
|
+
|
|
208
|
+
# 3. Khala: debilitation sign
|
|
209
|
+
elif DEBILITATION_SIGNS.get(name) == rashi:
|
|
210
|
+
avastha = "Khala"
|
|
211
|
+
condition_met = f"Debilitated in {rashi}"
|
|
212
|
+
|
|
213
|
+
# 4. Dukhita: combust (only applicable to non-Sun planets)
|
|
214
|
+
elif name != "Sun" and sun_lon is not None and name in COMBUSTION_DEG:
|
|
215
|
+
diff = _angular_diff(lon, sun_lon)
|
|
216
|
+
if diff <= COMBUSTION_DEG[name]:
|
|
217
|
+
avastha = "Dukhita"
|
|
218
|
+
condition_met = (
|
|
219
|
+
f"Combust — {diff:.1f}° from Sun "
|
|
220
|
+
f"(threshold {COMBUSTION_DEG[name]}°)"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# 5. Vikala: within 1° of any other planet (exclude Sun/Moon from trigger)
|
|
224
|
+
if avastha is None:
|
|
225
|
+
for other_name in _CLASSICAL_PLANETS:
|
|
226
|
+
if other_name == name or other_name in ("Sun", "Moon"):
|
|
227
|
+
continue
|
|
228
|
+
other = planet_map.get(other_name)
|
|
229
|
+
if other is None:
|
|
230
|
+
continue
|
|
231
|
+
diff = _angular_diff(lon, other["longitude"])
|
|
232
|
+
if diff <= 1.0:
|
|
233
|
+
avastha = "Vikala"
|
|
234
|
+
condition_met = f"Within 1° of {other_name} ({diff:.2f}°)"
|
|
235
|
+
break
|
|
236
|
+
|
|
237
|
+
if avastha is None:
|
|
238
|
+
# 6. Swastha: own sign or moolatrikona
|
|
239
|
+
if rashi in OWN_SIGNS.get(name, []) or MOOLATRIKONA.get(name) == rashi:
|
|
240
|
+
avastha = "Swastha"
|
|
241
|
+
condition_met = (
|
|
242
|
+
"Moolatrikona sign"
|
|
243
|
+
if MOOLATRIKONA.get(name) == rashi
|
|
244
|
+
else "Own sign"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# 7. Mudita: friend's sign
|
|
248
|
+
elif rashi in [
|
|
249
|
+
EXALTATION_SIGNS.get(f, "") or "" for f in PLANET_FRIENDS.get(name, [])
|
|
250
|
+
] or any(
|
|
251
|
+
rashi in OWN_SIGNS.get(friend, [])
|
|
252
|
+
for friend in PLANET_FRIENDS.get(name, [])
|
|
253
|
+
):
|
|
254
|
+
avastha = "Mudita"
|
|
255
|
+
condition_met = "Placed in a friend's sign"
|
|
256
|
+
|
|
257
|
+
# 8. Dina: enemy's sign
|
|
258
|
+
elif any(
|
|
259
|
+
rashi in OWN_SIGNS.get(enemy, [])
|
|
260
|
+
for enemy in PLANET_ENEMIES.get(name, [])
|
|
261
|
+
):
|
|
262
|
+
avastha = "Dina"
|
|
263
|
+
condition_met = "Placed in an enemy's sign"
|
|
264
|
+
|
|
265
|
+
# 9. Santha: neutral (default)
|
|
266
|
+
else:
|
|
267
|
+
avastha = "Santha"
|
|
268
|
+
condition_met = "Neutral sign"
|
|
269
|
+
|
|
270
|
+
meta = AVASTHAS[avastha]
|
|
271
|
+
|
|
272
|
+
# ------------------------------------------------------------------
|
|
273
|
+
# Baladi Avastha
|
|
274
|
+
# ------------------------------------------------------------------
|
|
275
|
+
baladi_name, baladi_strength = _get_baladi(deg_in_sign)
|
|
276
|
+
|
|
277
|
+
results.append(
|
|
278
|
+
{
|
|
279
|
+
"planet": name,
|
|
280
|
+
"rashi": rashi,
|
|
281
|
+
"house": house,
|
|
282
|
+
"avastha": avastha,
|
|
283
|
+
"strength_ratio": meta["strength"],
|
|
284
|
+
"nature": meta["nature"],
|
|
285
|
+
"condition_met": condition_met,
|
|
286
|
+
"is_retrograde": is_retro,
|
|
287
|
+
"baladi_avastha": baladi_name,
|
|
288
|
+
"baladi_strength": baladi_strength,
|
|
289
|
+
}
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
return results
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Ayanamsa modes and house systems from Swiss Ephemeris."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import swisseph as swe
|
|
8
|
+
|
|
9
|
+
# Expose all predefined sidereal modes (ayanamsas) from Swiss Ephemeris.
|
|
10
|
+
AYANAMSA_MODES: dict[str, dict[str, Any]] = {}
|
|
11
|
+
|
|
12
|
+
# Map readable names to swisseph constants.
|
|
13
|
+
_SIDM_MAP = {
|
|
14
|
+
"lahiri": swe.SIDM_LAHIRI,
|
|
15
|
+
"raman": swe.SIDM_RAMAN,
|
|
16
|
+
"krishnamurti": swe.SIDM_KRISHNAMURTI,
|
|
17
|
+
"yukteshwar": swe.SIDM_YUKTESHWAR,
|
|
18
|
+
"fagan_bradley": swe.SIDM_FAGAN_BRADLEY,
|
|
19
|
+
"galactic_0sag": swe.SIDM_GALCENT_0SAG,
|
|
20
|
+
"galactic_mula": swe.SIDM_GALEQU_MULA,
|
|
21
|
+
"true_chitra": swe.SIDM_TRUE_CITRA,
|
|
22
|
+
"true_revati": swe.SIDM_TRUE_REVATI,
|
|
23
|
+
"true_pushya": swe.SIDM_TRUE_PUSHYA,
|
|
24
|
+
"b1950": swe.SIDM_B1950,
|
|
25
|
+
"j1900": swe.SIDM_J1900,
|
|
26
|
+
"j2000": swe.SIDM_J2000,
|
|
27
|
+
"aryabhata": swe.SIDM_ARYABHATA,
|
|
28
|
+
"aryabhata_522": swe.SIDM_ARYABHATA_522,
|
|
29
|
+
"suryasiddhanta": swe.SIDM_SURYASIDDHANTA,
|
|
30
|
+
"suryasiddhanta_msun": swe.SIDM_SURYASIDDHANTA_MSUN,
|
|
31
|
+
"galactic_iau1958": swe.SIDM_GALEQU_IAU1958,
|
|
32
|
+
"galactic_true": swe.SIDM_GALEQU_TRUE,
|
|
33
|
+
"galactic_fiorenza": swe.SIDM_GALEQU_FIORENZA,
|
|
34
|
+
"deluce": swe.SIDM_DELUCE,
|
|
35
|
+
"djwhal_khul": swe.SIDM_DJWHAL_KHUL,
|
|
36
|
+
"babyl_kugler1": swe.SIDM_BABYL_KUGLER1,
|
|
37
|
+
"babyl_kugler2": swe.SIDM_BABYL_KUGLER2,
|
|
38
|
+
"babyl_kugler3": swe.SIDM_BABYL_KUGLER3,
|
|
39
|
+
"babyl_huber": swe.SIDM_BABYL_HUBER,
|
|
40
|
+
"babyl_etpsc": swe.SIDM_BABYL_ETPSC,
|
|
41
|
+
"babyl_britton": swe.SIDM_BABYL_BRITTON,
|
|
42
|
+
"aldebaran_15tau": swe.SIDM_ALDEBARAN_15TAU,
|
|
43
|
+
"ss_citra": swe.SIDM_SS_CITRA,
|
|
44
|
+
"ss_revati": swe.SIDM_SS_REVATI,
|
|
45
|
+
"valems_moon": swe.SIDM_VALENS_MOON,
|
|
46
|
+
"hipparchos": swe.SIDM_HIPPARCHOS,
|
|
47
|
+
"galalign_mardyks": swe.SIDM_GALALIGN_MARDYKS,
|
|
48
|
+
"galcent_cochrane": swe.SIDM_GALCENT_COCHRANE,
|
|
49
|
+
"galcent_mula_wilhelm": swe.SIDM_GALCENT_MULA_WILHELM,
|
|
50
|
+
"galcent_rgibrand": swe.SIDM_GALCENT_RGILBRAND,
|
|
51
|
+
"true_sheoran": swe.SIDM_TRUE_SHEORAN,
|
|
52
|
+
"ushashashi": swe.SIDM_USHASHASHI,
|
|
53
|
+
"lahiri_1940": swe.SIDM_LAHIRI_1940,
|
|
54
|
+
"lahiri_icrc": swe.SIDM_LAHIRI_ICRC,
|
|
55
|
+
"lahiri_vp285": swe.SIDM_LAHIRI_VP285,
|
|
56
|
+
"krishnamurti_vp291": swe.SIDM_KRISHNAMURTI_VP291,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for name, const in _SIDM_MAP.items():
|
|
60
|
+
try:
|
|
61
|
+
label = swe.get_ayanamsa_name(const) or name.replace("_", " ").title()
|
|
62
|
+
except Exception:
|
|
63
|
+
label = name.replace("_", " ").title()
|
|
64
|
+
AYANAMSA_MODES[name] = {
|
|
65
|
+
"id": const,
|
|
66
|
+
"label": label,
|
|
67
|
+
"description": f"Swiss Ephemeris sidereal mode {name}.",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
DEFAULT_AYANAMSA = "lahiri"
|
|
71
|
+
|
|
72
|
+
# House systems supported by Swiss Ephemeris.
|
|
73
|
+
HOUSE_SYSTEMS: dict[str, dict[str, Any]] = {
|
|
74
|
+
"P": {"name": "Placidus", "description": "Placidus house system (default)."},
|
|
75
|
+
"K": {"name": "Koch", "description": "Koch house system."},
|
|
76
|
+
"O": {"name": "Porphyrius", "description": "Porphyrius house system."},
|
|
77
|
+
"R": {"name": "Regiomontanus", "description": "Regiomontanus house system."},
|
|
78
|
+
"C": {"name": "Campanus", "description": "Campanus house system."},
|
|
79
|
+
"A": {"name": "Equal (0° Aries)", "description": "Equal houses from 0° Aries."},
|
|
80
|
+
"E": {"name": "Equal (Ascendant)", "description": "Equal houses from Ascendant."},
|
|
81
|
+
"V": {"name": "Vehlow", "description": "Vehlow equal houses."},
|
|
82
|
+
"X": {"name": "Axial/Aequalis", "description": "Axial system."},
|
|
83
|
+
"H": {"name": "Horizon", "description": "Horizon houses."},
|
|
84
|
+
"N": {"name": "Natural/Whole Sign", "description": "Whole sign houses."},
|
|
85
|
+
"B": {"name": "Pullen SD", "description": "Pullen sinodal delta."},
|
|
86
|
+
"G": {"name": "Gauquelin Sectors", "description": "Gauquelin sectors."},
|
|
87
|
+
"M": {"name": "Morinus", "description": "Morinus house system."},
|
|
88
|
+
"U": {"name": "Uranus/Krueger", "description": "Krugeian/Uranus houses."},
|
|
89
|
+
"T": {"name": "Topocentric", "description": "Topocentric house system."},
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
DEFAULT_HOUSE_SYSTEM = "P"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def list_ayanamsa_modes() -> dict[str, Any]:
|
|
96
|
+
return {
|
|
97
|
+
"default": DEFAULT_AYANAMSA,
|
|
98
|
+
"modes": AYANAMSA_MODES,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def list_house_systems() -> dict[str, Any]:
|
|
103
|
+
return {
|
|
104
|
+
"default": DEFAULT_HOUSE_SYSTEM,
|
|
105
|
+
"systems": HOUSE_SYSTEMS,
|
|
106
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Bhava Chalit Chart: house positions based on equal divisions from house cusps."""
|
|
2
|
+
|
|
3
|
+
from kundali_lib.vedic.constants import RASHIS
|
|
4
|
+
|
|
5
|
+
# Absolute longitude where each rashi begins (sidereal 0°)
|
|
6
|
+
RASHI_START: dict[str, float] = {rashi: i * 30.0 for i, rashi in enumerate(RASHIS)}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _normalize(lon: float) -> float:
|
|
10
|
+
"""Bring longitude into [0, 360)."""
|
|
11
|
+
return lon % 360.0
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _angular_distance(a: float, b: float) -> float:
|
|
15
|
+
"""Shortest signed arc from a to b along the zodiac circle, result in (-180, 180]."""
|
|
16
|
+
diff = (b - a) % 360.0
|
|
17
|
+
if diff > 180.0:
|
|
18
|
+
diff -= 360.0
|
|
19
|
+
return diff
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _reconstruct_cusp_longitudes(base_chart: dict) -> list[float]:
|
|
23
|
+
"""Convert (rashi, degree-within-sign) cusp data back to absolute longitudes.
|
|
24
|
+
|
|
25
|
+
``base_chart["houses"]`` maps ``"House_1"`` … ``"House_12"`` to rashi names.
|
|
26
|
+
``base_chart["house_cusp_degrees"]`` is a 12-element list of degrees-within-sign
|
|
27
|
+
(0–30) for each cusp, as produced by ``houses_dict_and_degrees()``.
|
|
28
|
+
"""
|
|
29
|
+
houses: dict[str, str] = base_chart["houses"]
|
|
30
|
+
cusp_degrees: list[float] = base_chart["house_cusp_degrees"]
|
|
31
|
+
cusps_abs: list[float] = []
|
|
32
|
+
for i in range(12):
|
|
33
|
+
rashi = houses[f"House_{i + 1}"]
|
|
34
|
+
deg = cusp_degrees[i]
|
|
35
|
+
cusps_abs.append(_normalize(RASHI_START[rashi] + deg))
|
|
36
|
+
return cusps_abs
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _build_bhava_boundaries(cusps_abs: list[float]) -> list[tuple[float, float]]:
|
|
40
|
+
"""Return 12 (start, end) boundary pairs using the midpoint method.
|
|
41
|
+
|
|
42
|
+
The boundary between house N and house N+1 is the midpoint of cusp_N and cusp_{N+1}
|
|
43
|
+
along the zodiac circle (handling wrap-around correctly).
|
|
44
|
+
"""
|
|
45
|
+
boundaries: list[tuple[float, float]] = []
|
|
46
|
+
midpoints: list[float] = []
|
|
47
|
+
for i in range(12):
|
|
48
|
+
c_this = cusps_abs[i]
|
|
49
|
+
c_next = cusps_abs[(i + 1) % 12]
|
|
50
|
+
# Arc from c_this → c_next (forward along zodiac)
|
|
51
|
+
arc = (c_next - c_this) % 360.0
|
|
52
|
+
mid = _normalize(c_this + arc / 2.0)
|
|
53
|
+
midpoints.append(mid)
|
|
54
|
+
|
|
55
|
+
for i in range(12):
|
|
56
|
+
start = midpoints[(i - 1) % 12]
|
|
57
|
+
end = midpoints[i]
|
|
58
|
+
boundaries.append((start, end))
|
|
59
|
+
|
|
60
|
+
return boundaries
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _planet_bhava(planet_lon: float, boundaries: list[tuple[float, float]]) -> int:
|
|
64
|
+
"""Return 1-based Bhava Chalit house number for a given planet longitude."""
|
|
65
|
+
for i, (start, end) in enumerate(boundaries):
|
|
66
|
+
# The span from start → end going forward along the zodiac
|
|
67
|
+
if start <= end:
|
|
68
|
+
if start <= planet_lon < end:
|
|
69
|
+
return i + 1
|
|
70
|
+
else:
|
|
71
|
+
# Wrap-around case (crosses 0°/360°)
|
|
72
|
+
if planet_lon >= start or planet_lon < end:
|
|
73
|
+
return i + 1
|
|
74
|
+
# Fallback — should not reach here with a well-formed chart
|
|
75
|
+
return 1
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_bhava_chalit(base_chart: dict) -> dict:
|
|
79
|
+
"""Compute the Bhava Chalit (Equal House from Cusps) chart.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
base_chart: Output of ``build_chart()``. Must contain ``planetary_positions``,
|
|
83
|
+
``houses``, ``house_cusp_degrees``, and ``ascendant``.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
A dict with absolute cusp longitudes, bhava boundaries, per-planet bhava
|
|
87
|
+
positions, and a list of planets whose house changed from the rashi chart.
|
|
88
|
+
"""
|
|
89
|
+
cusps_abs = _reconstruct_cusp_longitudes(base_chart)
|
|
90
|
+
boundaries = _build_bhava_boundaries(cusps_abs)
|
|
91
|
+
|
|
92
|
+
# Build output for house cusps
|
|
93
|
+
house_cusps_absolute: dict[str, float] = {
|
|
94
|
+
f"House_{i + 1}": round(cusps_abs[i], 4) for i in range(12)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
bhava_boundaries: dict[str, dict] = {}
|
|
98
|
+
for i, (start, end) in enumerate(boundaries):
|
|
99
|
+
bhava_boundaries[f"House_{i + 1}"] = {
|
|
100
|
+
"start": round(start, 4),
|
|
101
|
+
"end": round(end, 4),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
planetary_bhava_positions: list[dict] = []
|
|
105
|
+
planets_that_changed: list[str] = []
|
|
106
|
+
|
|
107
|
+
for planet in base_chart["planetary_positions"]:
|
|
108
|
+
pname = planet["name"]
|
|
109
|
+
lon = planet["longitude"]
|
|
110
|
+
regular_house: int = planet["house"]
|
|
111
|
+
bhava_house = _planet_bhava(_normalize(lon), boundaries)
|
|
112
|
+
changed = bhava_house != regular_house
|
|
113
|
+
|
|
114
|
+
planetary_bhava_positions.append(
|
|
115
|
+
{
|
|
116
|
+
"planet": pname,
|
|
117
|
+
"longitude": round(lon, 4),
|
|
118
|
+
"regular_house": regular_house,
|
|
119
|
+
"bhava_chalit_house": bhava_house,
|
|
120
|
+
"house_changed": changed,
|
|
121
|
+
"rashi": planet["rashi"],
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if changed:
|
|
126
|
+
planets_that_changed.append(pname)
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
"house_cusps_absolute": house_cusps_absolute,
|
|
130
|
+
"bhava_boundaries": bhava_boundaries,
|
|
131
|
+
"planetary_bhava_positions": planetary_bhava_positions,
|
|
132
|
+
"ascendant_bhava": 1,
|
|
133
|
+
"planets_that_changed_house": planets_that_changed,
|
|
134
|
+
"note": (
|
|
135
|
+
"Bhava Chalit shows actual house influence. Use alongside Rashi chart."
|
|
136
|
+
),
|
|
137
|
+
}
|