Files
Jyotisha/scripts/bhava_chalit.py
T

139 lines
4.0 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Bhava Chalit 宫位系统 v1.0
MIT License — 基于 dashaflow (adarshj322) 的等宫制实现
Bhava Chalit = 等分宫制,从上升中点(Lagna - 15°)开始,每宫30度
与整宫制(Whole Sign)的区别:靠近星座边界的行星可能跨宫
"""
from typing import Dict, List, Tuple
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
def calculate_bhava_chalit(asc_lon: float, raw_planets: Dict) -> Dict:
"""
Bhava Chalit 计算(等宫制从上升中点划分)
规则:
- 第1宫中点(Bhava Madhya) = Lagna 经度
- 第1宫起点 = Lagna - 15°
- 每宫跨度 = 30°
- 行星的Bhava宫位可能与其Rashi(整宫)宫位不同
Args:
asc_lon: 上升点黄道经度 (0-360)
raw_planets: {planet_name: {"lon": float, ...}}
每颗行星需要lon(黄道经度)和sign_idx(星座索引)
Returns:
dict: {planet_name: {"bhava_house": int, "rashi_house": int, "shifted": bool}}
"""
cusp_start = (asc_lon - 15.0) % 360.0
asc_sign_idx = int(asc_lon / 30) % 12
result = {}
for name, rp in raw_planets.items():
planet_lon = rp.get("lon", 0)
# 整宫制
sign_idx = rp.get("sign_idx", int(planet_lon / 30) % 12)
rashi_house = ((sign_idx - asc_sign_idx) % 12) + 1
# Bhava 宫位(等宫制)
diff = (planet_lon - cusp_start) % 360.0
bhava_house = int(diff / 30.0) + 1
if bhava_house > 12:
bhava_house = 12
result[name] = {
"bhava_house": bhava_house,
"rashi_house": rashi_house,
"shifted": bhava_house != rashi_house,
}
return result
def get_bhava_cusps(asc_lon: float) -> List[float]:
"""
获取所有12宫的Bhava Cusp(宫头)经度
Returns:
12个float,第1宫到第12宫的Cusp经度
"""
cusp_start = (asc_lon - 15.0) % 360.0
return [(cusp_start + i * 30.0) % 360.0 for i in range(12)]
def get_bhava_madhyas(asc_lon: float) -> List[float]:
"""
获取所有12宫的Bhava Madhya(宫中点)经度
Returns:
12个float,第1宫到第12宫的中点经度
"""
return [(asc_lon + i * 30.0) % 360.0 for i in range(12)]
def get_bhava_ranges(asc_lon: float) -> List[Tuple[float, float]]:
"""
获取每个宫位的起止范围
Returns:
12个tuple (start, end),第1宫到第12宫的经度范围
"""
cusps = get_bhava_cusps(asc_lon)
ranges = []
for i in range(12):
start = cusps[i]
end = cusps[(i + 1) % 12]
if end <= start:
end += 360
ranges.append((start, end))
return ranges
def planet_in_which_bhava(planet_lon: float, asc_lon: float) -> int:
"""
判断行星经度落在哪个Bhava宫(1-12)
"""
cusps = get_bhava_cusps(asc_lon)
for i in range(12):
start = cusps[i]
end = cusps[(i + 1) % 12]
if end <= start:
end += 360
plon = planet_lon if planet_lon >= start else planet_lon + 360
if start <= plon < end:
return i + 1
return 12
def cross_house_check(asc_lon: float, planet_name: str, planet_lon: float,
planet_sign_idx: int) -> Dict:
"""
跨宫检查:判断行星是否因Bhava Chalit而换宫
Returns:
{"planet": str, "rashi_house": int, "bhava_house": int,
"shifted": bool, "delta_degrees": float}
"""
asc_sign_idx = int(asc_lon / 30) % 12
rashi_house = ((planet_sign_idx - asc_sign_idx) % 12) + 1
bhava_house = planet_in_which_bhava(planet_lon, asc_lon)
delta = abs(bhava_house - rashi_house)
if delta > 6:
delta = 12 - delta
return {
"planet": planet_name,
"rashi_house": rashi_house,
"bhava_house": bhava_house,
"shifted": bhava_house != rashi_house,
"delta_houses": delta,
}