139 lines
4.0 KiB
Python
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,
|
|
}
|