Files

206 lines
7.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
吠陀占星精确相位模块 v1.0
基于度数的Drishti(相位)计算系统
支持:
- 标准7宫对冲相位
- 特殊相位: Mars(4/7/8), Jupiter(5/7/9), Saturn(3/7/10)
- 度数容许度(orb): 紧密/中等/松散三级
- 入相位(applying)/出相位(separating)判断
- 合相(conjunction)精度分析
"""
from typing import Dict, List, Tuple, Optional
# 标准容许度(度)
DEFAULT_ORBS = {
'Sun': 10, 'Moon': 10, 'Mars': 8, 'Mercury': 7,
'Jupiter': 9, 'Venus': 7, 'Saturn': 9, 'Rahu': 8, 'Ketu': 8,
'default': 7
}
ORBIT_CATEGORIES = {
'tight': 3, # 紧密相位(最强)
'moderate': 6, # 中等相位
'loose': 10, # 松散相位(最弱)
}
TIGHT_ORB_DEGREE = 1.0
# 特殊相位规则(从行星所在宫位算起)
SPECIAL_ASPECTS = {
'Mars': [4, 7, 8],
'Jupiter': [5, 7, 9],
'Saturn': [3, 7, 10],
}
# 所有行星都有7宫相位
ALL_HAVE_7TH = True
def calc_all_aspects(planet_longitudes: Dict[str, float],
ascendant_longitude: float) -> Dict:
"""
计算所有行星之间的精确相位关系
参数:
planet_longitudes: {'Sun': 12.5, 'Moon': 45.3, ...} 恒星黄道经度
ascendant_longitude: 上升点经度
返回: {
'aspects': [每对行星的相位详情],
'conjunctions': [合相详情],
'asc_aspects': [上升点被哪些星相位],
'tight_aspects': [紧密相位(<3°)],
'summary': 统计摘要
}
"""
planets = {k: v for k, v in planet_longitudes.items()
if k not in ('Ketu',) and isinstance(v, (int, float))}
# Ketu = Rahu + 180
if 'Rahu' in planet_longitudes and 'Ketu' not in planets:
planets['Ketu'] = (planet_longitudes['Rahu'] + 180) % 360
aspects = []
conjunctions = []
tight_aspects = []
planet_names = list(planets.keys())
for i, p1 in enumerate(planet_names):
for j, p2 in enumerate(planet_names):
if j <= i:
continue
lon1, lon2 = planets[p1], planets[p2]
pair_aspects = _calc_pair_aspects(p1, lon1, p2, lon2)
for asp in pair_aspects:
aspects.append(asp)
if asp['type'] == 'conjunction':
conjunctions.append(asp)
if asp['orb'] <= ORBIT_CATEGORIES['tight']:
tight_aspects.append(asp)
# 上升点相位
asc_aspects = []
for pname, plon in planets.items():
diff = abs(ascendant_longitude - plon) % 360
if diff > 180: diff = 360 - diff
if diff <= 15: # 上升点容许度
asc_aspects.append({
'planet': pname, 'degree_diff': round(diff, 2),
'orb_category': _orb_category(diff, 15),
'applying': plon > ascendant_longitude, # 简化判断
})
return {
'aspects': aspects,
'conjunctions': conjunctions,
'tight_aspects': tight_aspects,
'asc_aspects': asc_aspects,
'summary': {
'total_aspects': len(aspects),
'conjunctions': len(conjunctions),
'tight_aspects': len(tight_aspects),
'by_type': _count_by_type(aspects),
}
}
def _calc_pair_aspects(p1, lon1, p2, lon2) -> List[Dict]:
"""计算两颗行星之间的所有相位"""
results = []
diff = (lon2 - lon1) % 360
if diff > 180:
diff = 360 - diff
# 1. 合相 (conjunction): 同一星座内或跨星座但距离很近
max_conj_orb = max(DEFAULT_ORBS.get(p1, 7), DEFAULT_ORBS.get(p2, 7))
if diff <= max_conj_orb:
results.append({
'planet1': p1, 'planet2': p2,
'type': 'conjunction', 'aspect_degree': 0,
'actual_diff': round(diff, 2), 'orb': round(diff, 2),
'orb_category': _orb_category(diff, max_conj_orb),
'applying': (lon2 - lon1) % 360 < 180,
'strength': _aspect_strength(diff, max_conj_orb),
'description': f"{p1}{p2}合相(差距{diff:.1f}°)"
})
# 2. 对冲 (opposition): 7宫相位
opp_diff = abs(diff - 180)
opp_orb = max(DEFAULT_ORBS.get(p1, 7), DEFAULT_ORBS.get(p2, 7))
if opp_diff <= opp_orb and diff > max_conj_orb:
results.append({
'planet1': p1, 'planet2': p2,
'type': 'opposition', 'aspect_degree': 180,
'actual_diff': round(diff, 2), 'orb': round(opp_diff, 2),
'orb_category': _orb_category(opp_diff, opp_orb),
'applying': (lon2 - lon1) % 360 < 180,
'strength': _aspect_strength(opp_diff, opp_orb),
'description': f"{p1}对冲{p2}(差距{opp_diff:.1f}°)"
})
# 3. 特殊相位
for planet, aspect_degrees in SPECIAL_ASPECTS.items():
if planet == p1:
for asp_deg in aspect_degrees:
if asp_deg == 7:
continue # 已在对冲中处理
target = asp_deg * 30 # 转换为度数(每宫30°)
asp_diff = abs(diff - target)
if asp_diff > 180: asp_diff = 360 - asp_diff
asp_orb = 8 # 特殊相位容许度
if asp_diff <= asp_orb:
results.append({
'planet1': p1, 'planet2': p2,
'type': f'{planet}_aspect_{asp_deg}',
'aspect_degree': target,
'actual_diff': round(diff, 2), 'orb': round(asp_diff, 2),
'orb_category': _orb_category(asp_diff, asp_orb),
'applying': (lon2 - lon1) % 360 < 180,
'strength': _aspect_strength(asp_diff, asp_orb),
'description': f"{p1}({asp_deg}宫相位){p2}(差距{asp_diff:.1f}°)"
})
return results
def calc_house_aspects(planet_lon: float, planet_name: str,
asc_lon: float) -> Dict:
"""计算单颗行星对所有12宫的相位"""
planet_sign = int(planet_lon / 30) % 12
asc_sign = int(asc_lon / 30) % 12
planet_house = ((planet_sign - asc_sign) % 12) + 1
aspect_houses = [7] # 所有行星都有7宫相位
if planet_name in SPECIAL_ASPECTS:
aspect_houses = SPECIAL_ASPECTS[planet_name]
result = {'planet': planet_name, 'house': planet_house, 'aspects_to': {}}
for ah in aspect_houses:
target_house = ((planet_house - 1 + ah - 1) % 12) + 1
result['aspects_to'][target_house] = {
'from_house': planet_house,
'aspect_type': f'{ah}宫相位',
'is_special': ah != 7,
}
return result
def _orb_category(diff, max_orb):
if diff <= ORBIT_CATEGORIES['tight']: return 'tight'
if diff <= ORBIT_CATEGORIES['moderate']: return 'moderate'
return 'loose'
def _aspect_strength(diff, max_orb):
"""相位强度评分 0-100"""
if diff == 0: return 100
ratio = diff / max_orb
return max(0, round(100 * (1 - ratio), 1))
def _count_by_type(aspects):
counts = {}
for a in aspects:
t = a['type']
counts[t] = counts.get(t, 0) + 1
return counts