Files
Jyotisha/scripts/divisional_charts_extended.py
T
732642856 a4f8620a71 v6.2.0: 全面技法宝库升级 — 16个新模块 + 12个文件优化
## 新增模块 (16个)
### P0 精度修复
- ashtakavarga: calc_prastara_av() + calc_sodhita_av()
- kakshya.py: Kakshya评分系统 (8区间×3.75°)
- shadbala.py: Sputa Drishti + Yuddha Bala

### P1 核心升级
- bhava_bala.py: 宫位三元力量 (jyotishganit MIT)
- pancha_mahapurusha.py: PMC完整检测含4层失效条件
- sade_sati.py: Sade Sati+Kantaka Shani
- sudarshana_chakra.py: 三参考点盘+收敛分析
- tajika.py: Sahams 7→36 + Tajika Yogas 10种
- birth_time_rectifier.py: 生时矫正

### P2 覆盖扩展
- kp_system.py: KP Sublord+ABCD Significator (diliprk/VedicAstro MIT)
- synastry.py: 16因子合盘36分制 (dashaflow MIT)
- muhurtha_election.py: 6活动选举 (dashaflow MIT)
- career_analysis.py: 结构化事业引擎
- relationship_analysis.py: 结构化感情引擎
- conditional_dashas.py: Dwisaptati+Shattrimsa+Dwadashottari
- divisional_charts_extended: D81/D108/D144
- remedies.py: 5类补救系统

## 修改文件
jaimini/dasha_calculator/shadbala/SKILL.md/COVERAGE_AUDIT等12个

## 开源复用: 4个MIT项目
2026-06-11 19:03:21 +08:00

570 lines
23 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Divisional Charts Extended - D2-D60完整分盘宫位图计算器
印度占星 Shodasavarga16分盘)+ 扩展分盘系统
核心功能:
- 计算D1-D60所有分盘的行星位置
- 生成每个分盘的12宫位行星分布图
- 支持BPHS标准算法
- 提供分盘上升点计算
- 输出可视化宫位图数据
参考文献:
- Brihat Parashara Hora Shastra (BPHS) Chapter 6
- Phaladeepika by Mantreswara
- Jataka Parijata by Vaidyanatha Dikshita
"""
from typing import Dict, List, Tuple
from enum import Enum
class VargaType(Enum):
"""分盘类型枚举"""
D1 = (1, "Rashi", "本命盘")
D2 = (2, "Hora", "财富")
D3 = (3, "Drekkana", "兄弟姐妹")
D4 = (4, "Chaturthamsa", "财产/运气")
D5 = (5, "Panchamsa", "名声/权力")
D6 = (6, "Shashthamsa", "健康/敌人")
D7 = (7, "Saptamsa", "子女")
D8 = (8, "Ashtamsa", "突发事件")
D9 = (9, "Navamsa", "配偶/灵性")
D10 = (10, "Dasamsa", "事业")
D11 = (11, "Rudramsa", "破坏/转化")
D12 = (12, "Dwadasamsa", "父母")
D16 = (16, "Shodasamsa", "交通工具/舒适")
D20 = (20, "Vimsamsa", "灵性修行")
D24 = (24, "Chaturvimsamsa", "教育/学习")
D27 = (27, "Bhamsa", "力量/弱点")
D30 = (30, "Trimsamsa", "不幸/困难")
D40 = (40, "Khavedamsa", "吉凶效果")
D45 = (45, "Akshavedamsa", "全面判断")
D60 = (60, "Shashtiamsa", "前世业力")
D81 = (81, "Navamsa-Navamsa", "D9之D9精微分盘")
D108 = (108, "Dwadasamsa-Navamsa", "D12之D9精微分盘")
D144 = (144, "Dwadasamsa-Dwadasamsa", "D12之D12精微分盘")
def __init__(self, division: int, name: str, meaning: str):
self.division = division
self.varga_name = name
self.meaning = meaning
class DivisionalChartsCalculator:
"""分盘计算器"""
SIGNS = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"]
# 星座分类
MOVABLE_SIGNS = [0, 3, 6, 9] # Aries, Cancer, Libra, Capricorn
FIXED_SIGNS = [1, 4, 7, 10] # Taurus, Leo, Scorpio, Aquarius
DUAL_SIGNS = [2, 5, 8, 11] # Gemini, Virgo, Sagittarius, Pisces
ODD_SIGNS = [0, 2, 4, 6, 8, 10] # 奇数星座
EVEN_SIGNS = [1, 3, 5, 7, 9, 11] # 偶数星座
def __init__(self):
pass
def calculate_all_vargas(self, planet_positions: Dict[str, float],
asc_degree: float) -> Dict[str, Dict]:
"""
计算所有分盘的行星位置
Args:
planet_positions: {行星名: 黄道度数(0-360)}
asc_degree: 上升点黄道度数(0-360)
Returns:
{分盘名: {
"planets": {行星名: {"sign": 星座, "degree": 度数, "house": 宫位}},
"ascendant": {"sign": 星座, "degree": 度数},
"house_chart": [宫位1的行星列表, 宫位2的行星列表, ...]
}}
"""
results = {}
# 计算所有分盘
for varga_type in VargaType:
varga_result = self._calculate_single_varga(
varga_type, planet_positions, asc_degree
)
results[varga_type.varga_name] = varga_result
return results
def _calculate_single_varga(self, varga_type: VargaType,
planet_positions: Dict[str, float],
asc_degree: float) -> Dict:
"""计算单个分盘"""
division = varga_type.division
# 计算分盘上升点
varga_asc = self._calculate_varga_position(asc_degree, division)
varga_asc_sign = int(varga_asc // 30)
varga_asc_degree = varga_asc % 30
# 计算所有行星的分盘位置
varga_planets = {}
for planet, degree in planet_positions.items():
varga_pos = self._calculate_varga_position(degree, division)
varga_sign = int(varga_pos // 30)
varga_degree = varga_pos % 30
# 计算宫位(从上升点开始)
house = ((varga_sign - varga_asc_sign) % 12) + 1
varga_planets[planet] = {
"sign": self.SIGNS[varga_sign],
"sign_index": varga_sign,
"degree": round(varga_degree, 4),
"house": house,
"absolute_degree": round(varga_pos, 4)
}
# 生成宫位图(12个宫位,每个宫位包含的行星列表)
house_chart = [[] for _ in range(12)]
for planet, data in varga_planets.items():
house_chart[data["house"] - 1].append(planet)
return {
"division": division,
"name": varga_type.varga_name,
"meaning": varga_type.meaning,
"ascendant": {
"sign": self.SIGNS[varga_asc_sign],
"sign_index": varga_asc_sign,
"degree": round(varga_asc_degree, 4)
},
"planets": varga_planets,
"house_chart": house_chart
}
def _calculate_varga_position(self, degree: float, division: int) -> float:
"""
计算分盘位置(BPHS标准算法)
Args:
degree: 黄道度数(0-360)
division: 分盘数(2-60)
Returns:
分盘中的黄道度数(0-360)
"""
# 获取星座索引和星座内度数
sign_index = int(degree // 30)
sign_degree = degree % 30
# 根据不同分盘使用不同算法
if division == 2:
return self._calculate_d2(sign_index, sign_degree)
elif division == 3:
return self._calculate_d3(sign_index, sign_degree)
elif division == 4:
return self._calculate_d4(sign_index, sign_degree)
elif division == 5:
return self._calculate_d5(sign_index, sign_degree)
elif division == 6:
return self._calculate_d6(sign_index, sign_degree)
elif division == 7:
return self._calculate_d7(sign_index, sign_degree)
elif division == 8:
return self._calculate_d8(sign_index, sign_degree)
elif division == 9:
return self._calculate_d9(sign_index, sign_degree)
elif division == 10:
return self._calculate_d10(sign_index, sign_degree)
elif division == 11:
return self._calculate_d11(sign_index, sign_degree)
elif division == 12:
return self._calculate_d12(sign_index, sign_degree)
elif division == 16:
return self._calculate_d16(sign_index, sign_degree)
elif division == 20:
return self._calculate_d20(sign_index, sign_degree)
elif division == 24:
return self._calculate_d24(sign_index, sign_degree)
elif division == 27:
return self._calculate_d27(sign_index, sign_degree)
elif division == 30:
return self._calculate_d30(sign_index, sign_degree)
elif division == 40:
return self._calculate_d40(sign_index, sign_degree)
elif division == 45:
return self._calculate_d45(sign_index, sign_degree)
elif division == 60:
return self._calculate_d60(sign_index, sign_degree)
elif division == 81:
return self._calculate_d81(sign_index, sign_degree)
elif division == 108:
return self._calculate_d108(sign_index, sign_degree)
elif division == 144:
return self._calculate_d144(sign_index, sign_degree)
else:
# 通用算法(适用于其他分盘)
return self._calculate_generic_varga(sign_index, sign_degree, division)
def _calculate_d2(self, sign_index: int, sign_degree: float) -> float:
"""D2 Hora - 财富分盘"""
# 奇数星座:0-15度→Leo15-30度→Cancer
# 偶数星座:0-15度→Cancer15-30度→Leo
if sign_index in self.ODD_SIGNS:
if sign_degree < 15:
return 4 * 30 + sign_degree * 2 # Leo
else:
return 3 * 30 + (sign_degree - 15) * 2 # Cancer
else:
if sign_degree < 15:
return 3 * 30 + sign_degree * 2 # Cancer
else:
return 4 * 30 + (sign_degree - 15) * 2 # Leo
def _calculate_d3(self, sign_index: int, sign_degree: float) -> float:
"""D3 Drekkana - 兄弟姐妹分盘"""
# 每个星座分为3个10度区间
# 第1个10度→本星座,第2个10度→第5个星座,第3个10度→第9个星座
drekkana = int(sign_degree // 10)
offset = [0, 4, 8][drekkana]
varga_sign = (sign_index + offset) % 12
varga_degree = (sign_degree % 10) * 3
return varga_sign * 30 + varga_degree
def _calculate_d4(self, sign_index: int, sign_degree: float) -> float:
"""D4 Chaturthamsa - 财产/运气分盘"""
# 每个星座分为4个7.5度区间
part = int(sign_degree // 7.5)
varga_sign = (sign_index + part * 3) % 12
varga_degree = (sign_degree % 7.5) * 4
return varga_sign * 30 + varga_degree
def _calculate_d7(self, sign_index: int, sign_degree: float) -> float:
"""D7 Saptamsa - 子女分盘"""
# 每个星座分为7个约4.286度区间
part = int(sign_degree // (30/7))
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 6 + part) % 12
varga_degree = (sign_degree % (30/7)) * 7
return varga_sign * 30 + varga_degree
def _calculate_d9(self, sign_index: int, sign_degree: float) -> float:
"""D9 Navamsa - 配偶/灵性分盘(最重要的分盘)"""
# 每个星座分为9个3.333度区间
part = int(sign_degree // (30/9))
# 根据星座类型确定起始点 (BPHS标准)
# Movable(白羊/巨蟹/天秤/摩羯)=从本星座开始
# Fixed(金牛/狮子/天蝎/水瓶)=从第5个星座开始(+4)
# Dual(双子/处女/射手/双鱼)=从第9个星座开始(+8)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 4) % 12
else: # DUAL_SIGNS
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % (30/9)) * 9
return varga_sign * 30 + varga_degree
def _calculate_d10(self, sign_index: int, sign_degree: float) -> float:
"""D10 Dasamsa - 事业分盘"""
# 每个星座分为10个3度区间
part = int(sign_degree // 3)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % 3) * 10
return varga_sign * 30 + varga_degree
def _calculate_d12(self, sign_index: int, sign_degree: float) -> float:
"""D12 Dwadasamsa - 父母分盘"""
# 每个星座分为12个2.5度区间
part = int(sign_degree // 2.5)
varga_sign = (sign_index + part) % 12
varga_degree = (sign_degree % 2.5) * 12
return varga_sign * 30 + varga_degree
def _calculate_d16(self, sign_index: int, sign_degree: float) -> float:
"""D16 Shodasamsa - 交通工具/舒适分盘"""
# 每个星座分为16个1.875度区间
part = int(sign_degree // 1.875)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 4) % 12
else:
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % 1.875) * 16
return varga_sign * 30 + varga_degree
def _calculate_d20(self, sign_index: int, sign_degree: float) -> float:
"""D20 Vimsamsa - 灵性修行分盘"""
# 每个星座分为20个1.5度区间
part = int(sign_degree // 1.5)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 8) % 12
else:
start = (sign_index + 4) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % 1.5) * 20
return varga_sign * 30 + varga_degree
def _calculate_d24(self, sign_index: int, sign_degree: float) -> float:
"""D24 Chaturvimsamsa - 教育/学习分盘"""
# 每个星座分为24个1.25度区间
part = int(sign_degree // 1.25)
if sign_index in self.ODD_SIGNS:
varga_sign = (4 + part) % 12 # 从Leo开始
else:
varga_sign = (3 + part) % 12 # 从Cancer开始
varga_degree = (sign_degree % 1.25) * 24
return varga_sign * 30 + varga_degree
def _calculate_d27(self, sign_index: int, sign_degree: float) -> float:
"""D27 Bhamsa - 力量/弱点分盘"""
# 每个星座分为27个1.111度区间
part = int(sign_degree // (30/27))
if sign_index in self.ODD_SIGNS:
start = sign_index
else:
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % (30/27)) * 27
return varga_sign * 30 + varga_degree
def _calculate_d30(self, sign_index: int, sign_degree: float) -> float:
"""D30 Trimsamsa - 不幸/困难分盘(特殊算法)"""
# D30使用特殊的不等分算法
# 奇数星座:Mars(5°), Saturn(5°), Jupiter(8°), Mercury(7°), Venus(5°)
# 偶数星座:Venus(5°), Mercury(7°), Jupiter(8°), Saturn(5°), Mars(5°)
if sign_index in self.ODD_SIGNS:
if sign_degree < 5:
varga_sign = 0 # Aries (Mars)
varga_degree = sign_degree * 6
elif sign_degree < 10:
varga_sign = 10 # Aquarius (Saturn)
varga_degree = (sign_degree - 5) * 6
elif sign_degree < 18:
varga_sign = 8 # Sagittarius (Jupiter)
varga_degree = (sign_degree - 10) * 3.75
elif sign_degree < 25:
varga_sign = 2 # Gemini (Mercury)
varga_degree = (sign_degree - 18) * 4.286
else:
varga_sign = 1 # Taurus (Venus)
varga_degree = (sign_degree - 25) * 6
else:
if sign_degree < 5:
varga_sign = 1 # Taurus (Venus)
varga_degree = sign_degree * 6
elif sign_degree < 12:
varga_sign = 2 # Gemini (Mercury)
varga_degree = (sign_degree - 5) * 4.286
elif sign_degree < 20:
varga_sign = 8 # Sagittarius (Jupiter)
varga_degree = (sign_degree - 12) * 3.75
elif sign_degree < 25:
varga_sign = 10 # Aquarius (Saturn)
varga_degree = (sign_degree - 20) * 6
else:
varga_sign = 0 # Aries (Mars)
varga_degree = (sign_degree - 25) * 6
return varga_sign * 30 + varga_degree
def _calculate_d40(self, sign_index: int, sign_degree: float) -> float:
"""D40 Khavedamsa - 吉凶效果分盘"""
# 每个星座分为40个0.75度区间
part = int(sign_degree // 0.75)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 8) % 12
else:
start = (sign_index + 4) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % 0.75) * 40
return varga_sign * 30 + varga_degree
def _calculate_d45(self, sign_index: int, sign_degree: float) -> float:
"""D45 Akshavedamsa - 全面判断分盘"""
# 每个星座分为45个0.667度区间
part = int(sign_degree // (30/45))
if sign_index in self.ODD_SIGNS:
start = sign_index
else:
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % (30/45)) * 45
return varga_sign * 30 + varga_degree
def _calculate_d60(self, sign_index: int, sign_degree: float) -> float:
"""D60 Shashtiamsa - 前世业力分盘(最精细的分盘)"""
# 每个星座分为60个0.5度区间
part = int(sign_degree // 0.5)
varga_sign = (sign_index + part) % 12
varga_degree = (sign_degree % 0.5) * 60
return varga_sign * 30 + varga_degree
def _calculate_d81(self, sign_index: int, sign_degree: float) -> float:
"""D81 Navamsa-Navamsa — D9的D9精微分盘"""
# 先计算D9位置
d9_lon = self._calculate_d9(sign_index, sign_degree)
d9_sign = int(d9_lon / 30) % 12
d9_deg = d9_lon % 30
# 再对D9结果计算一次D9
return self._calculate_d9(d9_sign, d9_deg)
def _calculate_d108(self, sign_index: int, sign_degree: float) -> float:
"""D108 Dwadasamsa-Navamsa — D12的D9精微分盘"""
d9_lon = self._calculate_d9(sign_index, sign_degree)
d9_sign = int(d9_lon / 30) % 12
d9_deg = d9_lon % 30
return self._calculate_d12(d9_sign, d9_deg)
def _calculate_d144(self, sign_index: int, sign_degree: float) -> float:
"""D144 Dwadasamsa-Dwadasamsa — D12的D12精微分盘"""
d12_lon = self._calculate_d12(sign_index, sign_degree)
d12_sign = int(d12_lon / 30) % 12
d12_deg = d12_lon % 30
return self._calculate_d12(d12_sign, d12_deg)
def _calculate_d5(self, sign_index: int, sign_degree: float) -> float:
"""D5 Panchamsa - 名声/权力分盘"""
part = int(sign_degree // 6)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % 6) * 5
return varga_sign * 30 + varga_degree
def _calculate_d6(self, sign_index: int, sign_degree: float) -> float:
"""D6 Shashthamsa - 健康/敌人分盘"""
part = int(sign_degree // 5)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 6 + part) % 12
varga_degree = (sign_degree % 5) * 6
return varga_sign * 30 + varga_degree
def _calculate_d8(self, sign_index: int, sign_degree: float) -> float:
"""D8 Ashtamsa - 突发事件分盘"""
part = int(sign_degree // 3.75)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % 3.75) * 8
return varga_sign * 30 + varga_degree
def _calculate_d11(self, sign_index: int, sign_degree: float) -> float:
"""D11 Rudramsa - 破坏/转化分盘"""
part = int(sign_degree // (30/11))
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % (30/11)) * 11
return varga_sign * 30 + varga_degree
def _calculate_generic_varga(self, sign_index: int, sign_degree: float, division: int) -> float:
"""通用分盘算法(适用于其他分盘)"""
part = int(sign_degree // (30/division))
varga_sign = (sign_index + part) % 12
varga_degree = (sign_degree % (30/division)) * division
return varga_sign * 30 + varga_degree
def generate_house_chart_ascii(self, house_chart: List[List[str]]) -> str:
"""
生成ASCII格式的宫位图
Args:
house_chart: 12个宫位的行星列表
Returns:
ASCII格式的宫位图字符串
"""
# 北印度风格宫位图(菱形)
chart = f"""
┌─────────┬─────────┬─────────┐
│ 12 │ 1 │ 2 │
{self._format_planets(house_chart[11]):7}{self._format_planets(house_chart[0]):7}{self._format_planets(house_chart[1]):7}
├─────────┼─────────┼─────────┤
│ 11 │ │ 3 │
{self._format_planets(house_chart[10]):7} │ ASC │ {self._format_planets(house_chart[2]):7}
├─────────┼─────────┼─────────┤
│ 10 │ 9 │ 4 │
{self._format_planets(house_chart[9]):7}{self._format_planets(house_chart[8]):7}{self._format_planets(house_chart[3]):7}
├─────────┼─────────┼─────────┤
│ 9 │ 8 │ 5 │
{self._format_planets(house_chart[8]):7}{self._format_planets(house_chart[7]):7}{self._format_planets(house_chart[4]):7}
├─────────┼─────────┼─────────┤
│ 8 │ 7 │ 6 │
{self._format_planets(house_chart[7]):7}{self._format_planets(house_chart[6]):7}{self._format_planets(house_chart[5]):7}
└─────────┴─────────┴─────────┘
"""
return chart
def _format_planets(self, planets: List[str]) -> str:
"""格式化行星列表为简写"""
if not planets:
return " "
# 行星简写
abbrev = {
"Sun": "Su", "Moon": "Mo", "Mars": "Ma", "Mercury": "Me",
"Jupiter": "Ju", "Venus": "Ve", "Saturn": "Sa",
"Rahu": "Ra", "Ketu": "Ke"
}
short = [abbrev.get(p, p[:2]) for p in planets]
return " ".join(short)[:7].ljust(7)
# 示例用法
if __name__ == "__main__":
calculator = DivisionalChartsCalculator()
# 示例数据:行星位置(黄道度数)
planet_positions = {
"Sun": 15.5, # Aries 15.5°
"Moon": 125.3, # Leo 5.3°
"Mars": 285.7, # Capricorn 15.7°
"Mercury": 25.2, # Aries 25.2°
"Jupiter": 95.8, # Cancer 5.8°
"Venus": 335.4, # Pisces 5.4°
"Saturn": 245.6, # Sagittarius 5.6°
"Rahu": 185.9, # Libra 5.9°
"Ketu": 5.9 # Aries 5.9°
}
asc_degree = 10.0 # Aries 10°
# 计算所有分盘
all_vargas = calculator.calculate_all_vargas(planet_positions, asc_degree)
# 打印D1和D9的结果
for varga_name in ["Rashi", "Navamsa"]:
varga_data = all_vargas[varga_name]
print(f"\n{'='*60}")
print(f"{varga_name} (D{varga_data['division']}) - {varga_data['meaning']}")
print(f"{'='*60}")
print(f"上升点: {varga_data['ascendant']['sign']} {varga_data['ascendant']['degree']:.2f}°")
print(f"\n行星位置:")
for planet, data in varga_data['planets'].items():
print(f" {planet:10}{data['sign']:12} {data['degree']:6.2f}° (第{data['house']}宫)")
print(f"\n宫位图:")
print(calculator.generate_house_chart_ascii(varga_data['house_chart']))