v3.7.0: 新增7大模块 - BPHS十六分盘/精确相位/Jaimini/高级Nakshatra/Argala门闩/Tajika年运/合盘分析
- varga.py: D2-D60 BPHS十六分盘完整计算 - aspects.py: 度数精确相位系统(tight/moderate/loose) - jaimini.py: Chara Karaka 7/8 + Chara Dasha + Karakamsha - nakshatra_advanced.py: Tara Bala + Sub-Lord KP系统 - argala.py: Argala门闩 + Virodha反干预 - tajika.py: Muntha/YearLord/Mudda Dasha/Tri-Pataka - synastry.py: Ashta Koota 36分制 + Mangal Dosha + Papasamya 引擎升级至v3.7.0, 21个子命令全链路验证通过
This commit is contained in:
@@ -1,5 +1,72 @@
|
||||
# 印度占星 Skill 更新日志
|
||||
|
||||
## v3.7.0(2026-04-25)— 7大新模块:BPHS十六分盘+精确相位+Jaimini+高级Nakshatra+Argala+Tajika+合盘
|
||||
|
||||
### 新增模块(7个)
|
||||
|
||||
- **`scripts/varga.py`**:BPHS Shodasavarga十六分盘完整计算
|
||||
- 支持全部16个分盘:D2/D3/D4/D7/D9/D10/D12/D16/D20/D24/D27/D30/D40/D45/D60
|
||||
- 每个分盘输出精确度数(非仅星座名)
|
||||
- D30 Trimsamsa 特殊不等宽映射
|
||||
- D9 含 Jaimini 分析(7宫/Venus/Jupiter/尊严状态)
|
||||
- D60 含业力分析(角宫吉凶星分布)
|
||||
|
||||
- **`scripts/aspects.py`**:度数精确相位系统(Drishti)
|
||||
- 标准7宫对冲 + 火星4/7/8 + 木星5/7/9 + 土星3/7/10
|
||||
- Orb分类:tight(≤3°) / moderate(≤6°) / loose(≤10°)
|
||||
- 计算每个相位的入相位/出相位状态
|
||||
- 合相精度分析
|
||||
|
||||
- **`scripts/jaimini.py`**:Jaimini系统完整实现
|
||||
- `calc_chara_karaka_7()`:7行星 Chara Karaka(AK→DK)
|
||||
- `calc_chara_karaka_8()`:8行星 Chara Karaka(含Rahu逆行度数处理)
|
||||
- `calc_chara_dasha()`:星座大运(基于上升奇偶性决定方向)
|
||||
- `calc_karakamsha()`:灵魂方向分析(DK的D9位置解读)
|
||||
|
||||
- **`scripts/nakshatra_advanced.py`**:高级Nakshatra分析
|
||||
- 精确Nakshatra定位(名称/Pada/度数/Gana/元素)
|
||||
- `calc_tara_bala()`:9循环Tara关系分析
|
||||
- `calc_sub_lord()`:KP系统 Sub-Lord 计算
|
||||
- `nakshatra_compatibility()`:Tara+元素+Gana综合兼容性
|
||||
|
||||
- **`scripts/argala.py`**:Argala门闩系统
|
||||
- 主Argala:2/4/11宫 → 财富/幸福/收益
|
||||
- 副Argala:5/8宫 → 权力/转化
|
||||
- Virodha(阻断):12→2, 10→4, 3→11, 9→5, 2→8
|
||||
- 净评分计算和吉凶判定
|
||||
|
||||
- **`scripts/tajika.py`**:Tajika/Varshaphala年运盘
|
||||
- `calc_muntha()`:年度上升进展
|
||||
- `calc_year_lord()`:年度守护星 + 辅助星(2/5/9/11宫主)
|
||||
- `calc_mudda_dasha()`:12个月比例大运
|
||||
- `calc_tri_pataka()`:三旗系统评估
|
||||
|
||||
- **`scripts/synastry.py`**:合盘分析系统
|
||||
- Ashta Koota 36分制(8维度:Varna/Vashya/Tara/Yoni/Graha Maitri/Gana/Bhakuta/Nadi)
|
||||
- Mangal Dosha 检查(火星在1/2/4/7/8/12宫)
|
||||
- Papasamya 凶星抵消度评估
|
||||
- Dasha时间线兼容性分析
|
||||
- 自动生成化解建议
|
||||
|
||||
### 引擎升级(jyotish_engine.py)
|
||||
|
||||
- 版本 v3.6.0 → **v3.7.0**
|
||||
- 新增7个CLI子命令:`varga-full` / `aspects` / `jaimini` / `nakshatra-adv` / `argala` / `tajika` / `synastry`
|
||||
- 总子命令数:14 → **21**
|
||||
- 所有新模块通过一楠星盘验证(REDACTED_DATE 14:45)
|
||||
|
||||
### 验证结果
|
||||
|
||||
| 模块 | 子命令 | 一楠星盘验证 | 关键输出 |
|
||||
|------|--------|-------------|---------|
|
||||
| varga | varga-full | ✅ | D9 Navamsa 精确度数+尊严 |
|
||||
| aspects | aspects | ✅ | 6个精确相位(Moon-Saturn合相等)|
|
||||
| jaimini | jaimini | ✅ | AK=Venus, DK=Mars, Chara Dasha序列 |
|
||||
| nakshatra | nakshatra-adv | ✅ | 9行星Tara Bala, Sub-Lord |
|
||||
| argala | argala | ✅ | 9行星门闩分析 |
|
||||
| tajika | tajika | ✅ | 33岁 Muntha=金牛座, YearLord=Venus |
|
||||
| synastry | synastry | ✅ | Ashta Koota 26/36 (72.2%) |
|
||||
|
||||
## v3.6.0(2026-04-24)— CNWU16二次借鉴:report_builder + R2b列校验 + P3/P8/冲突仲裁
|
||||
|
||||
### 新增文件
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: jyotish-vedic-astrology
|
||||
version: 3.6.0
|
||||
description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。覆盖行星配置、Yoga格局、Nakshatra解读、宫位分析、现代生活场景映射、现代措辞解读、案例对比分析、自动出生时间矫正、常见误判纠错、Dasha+Transit推运、精确预测、PDF星盘读取、Swiss Ephemeris计算引擎、星盘计算、分盘计算、名人案例查询、Shadbala六重力量、Ashtakavarga八分法(BPHS完整表SAV=337)、Hermes记忆系统、事件预测、R1-R10数学验证(含R2b BAV列→SAV列校验)、P1-P12行星审计(含P3仓库耦合+P8年龄状态+冲突仲裁3条规则)、验前事、MD→HTML报告生成(羊皮纸主题)。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、吠陀占星、印占、PDF星盘、读取PDF、分析PDF星盘、矫正出生时间、出生时间验证、生时矫正、现代解读、现代措辞、误判纠错、错题本、Varga分盘、全球占星师方法论、三合盘、综合分析、过境分析、Double Transit、Sade Sati、合盘、婚姻匹配、关系分析、Koota、Mangal Dosha、年运盘、Varshaphala、太阳返照、Tajika、星宿速查、综合解盘工作流、应期预测、推运应期、事件时机、什么时候结婚、什么时候升职、什么时候发财、Argala、门闩、行星干预、Dasa收敛、Yogini大运、Chara Dasha、AI解盘、算星盘、排盘、计算星盘、查名人、Shadbala、六重力量、Ashtakavarga、八分法、行星力量、记忆系统、事件预测、验证、校验、审计、验前事、R1-R10、P1-P12、仓库耦合、冲突仲裁、报告生成、HTML报告。
|
||||
version: 3.7.0
|
||||
description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。覆盖行星配置、Yoga格局、Nakshatra解读、宫位分析、现代生活场景映射、现代措辞解读、案例对比分析、自动出生时间矫正、常见误判纠错、Dasha+Transit推运、精确预测、PDF星盘读取、Swiss Ephemeris计算引擎、星盘计算、分盘计算、名人案例查询、Shadbala六重力量、Ashtakavarga八分法(BPHS完整表SAV=337)、Hermes记忆系统、事件预测、R1-R10数学验证(含R2b BAV列→SAV列校验)、P1-P12行星审计(含P3仓库耦合+P8年龄状态+冲突仲裁3条规则)、验前事、MD→HTML报告生成(羊皮纸主题)、BPHS十六分盘精确计算(D2-D60)、度数精确相位系统(Drishti)、Jaimini完整系统(Chara Karaka 7/8+Chara Dasha+Karakamsha)、高级Nakshatra分析(Tara Bala+Sub-Lord KP系统)、Argala门闩系统(Virodha反干预)、Tajika年运盘(Muntha+YearLord+Mudda Dasha+Tri-Pataka三旗)、合盘分析(Ashta Koota 36分制+Mangal Dosha+Papasamya+Dasha兼容性)。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、吠陀占星、印占、PDF星盘、读取PDF、分析PDF星盘、矫正出生时间、出生时间验证、生时矫正、现代解读、现代措辞、误判纠错、错题本、Varga分盘、全球占星师方法论、三合盘、综合分析、过境分析、Double Transit、Sade Sati、合盘、婚姻匹配、关系分析、Koota、Mangal Dosha、年运盘、Varshaphala、太阳返照、Tajika、星宿速查、综合解盘工作流、应期预测、推运应期、事件时机、什么时候结婚、什么时候升职、什么时候发财、Argala、门闩、行星干预、Dasa收敛、Yogini大运、Chara Dasha、AI解盘、算星盘、排盘、计算星盘、查名人、Shadbala、六重力量、Ashtakavarga、八分法、行星力量、记忆系统、事件预测、验证、校验、审计、验前事、R1-R10、P1-P12、仓库耦合、冲突仲裁、报告生成、HTML报告、精确相位、Drishti、Jaimini、Chara Karaka、Atmakaraka、Darakaraka、Karakamsha、Tara Bala、Sub-Lord、KP系统、Navamsa、D9、D60、Shashtyamsa、十六分盘、门闩分析、Muntha、年主星、三旗系统、合盘评分、Nadi Koota、Gana、Yoni、Papasamya、Dasha兼容。
|
||||
---
|
||||
|
||||
# 印度占星专业解盘与推运系统
|
||||
@@ -193,7 +193,7 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力
|
||||
|
||||
### 13. 计算引擎集成(Swiss Ephemeris + 数据库)⭐ v3.4.0
|
||||
|
||||
**统一引擎入口**:`scripts/jyotish_engine.py` v3.4.0(基于 Swiss Ephemeris 天文计算库)
|
||||
**统一引擎入口**:`scripts/jyotish_engine.py` v3.7.0(基于 Swiss Ephemeris 天文计算库)
|
||||
|
||||
**调用方式**:AI 通过 `execute_command` 调用以下子命令(所有输出为 JSON):
|
||||
|
||||
@@ -204,7 +204,7 @@ SCRIPT=~/.workbuddy/skills/jyotish-vedic-astrology/scripts/jyotish_engine.py
|
||||
$PYTHON $SCRIPT <子命令> [参数]
|
||||
```
|
||||
|
||||
**13大子命令**:
|
||||
**13大子命令** → **21大子命令**(v3.7 升级):
|
||||
|
||||
| 子命令 | 功能 | 典型用法 |
|
||||
|--------|------|----------|
|
||||
@@ -221,23 +221,36 @@ $PYTHON $SCRIPT <子命令> [参数]
|
||||
| `memory` | ⭐ Hermes记忆系统(store/search/context/stats) | `memory --action store --content "..." --tags "chart" --importance 8` |
|
||||
| `validate` | ⭐ R1-R10数学验证(SAV/BAV/延伸角/Rahu-Ketu/逆行/Dasha/完整性/度数/宫位) | `validate --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8` |
|
||||
| `audit` | ⭐ P1-P12行星审计管线(Identity/Health/Resource/SAV/Dignity/Shadbala/Aspects/Nakshatra/Yogas) | `audit --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8` |
|
||||
| `varga-full` | ⭐ v3.7 BPHS十六分盘精确计算(D2-D60全部16分盘,精确度数输出) | `varga-full --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8 --divisions D9,D60` |
|
||||
| `aspects` | ⭐ v3.7 度数精确相位系统(tight/moderate/loose + 入相位/出相位) | `aspects --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8` |
|
||||
| `jaimini` | ⭐ v3.7 Jaimini完整系统(Chara Karaka 7/8 + Chara Dasha + Karakamsha) | `jaimini --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8 --mode all` |
|
||||
| `nakshatra-adv` | ⭐ v3.7 高级Nakshatra(Tara Bala + Sub-Lord KP + 兼容性) | `nakshatra-adv --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8 --mode all` |
|
||||
| `argala` | ⭐ v3.7 Argala门闩系统(主/副Argala + Virodha反干预 + 净评分) | `argala --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8` |
|
||||
| `tajika` | ⭐ v3.7 Tajika年运盘(Muntha + YearLord + Mudda Dasha + Tri-Pataka) | `tajika --year REDACTED_YEAR --month 4 --day 17 --hour 14 --minute 45 --lat 36.6 --lon 114.5 --tz 8 --age 33` |
|
||||
| `synastry` | ⭐ v3.7 合盘分析(Ashta Koota 36分 + Mangal Dosha + Papasamya) | `synastry --moon1 310.89 --moon2 45.5 --mars1 90.43 --mars2 120.3` |
|
||||
|
||||
**外部数据源**(引擎自动读取):
|
||||
- 验证数据库:`~/WorkBuddy/Claw/vedic_astrology_validation.db`(15,840条案例,10种技法准确率)
|
||||
- 名人CSV:`~/WorkBuddy/Claw/vedastro_data/PersonList-15k.csv`(15,807条AA级数据)
|
||||
- 过境配置:`~/WorkBuddy/Claw/月运过境配置-2026-2028.json`(36个月行星位置)
|
||||
|
||||
**典型工作流**:
|
||||
**典型工作流**(v3.7 升级):
|
||||
1. 用户给出生信息 → `chart` 计算星盘 → 获取行星位置、宫位、Nakshatra
|
||||
2. 从 chart 结果取月亮经度 → `dasha` 计算当前大运
|
||||
3. 从 chart 结果取行星配置 → `yoga` 识别格局
|
||||
4. `shadbala` 计算六重力量 → 量化行星强度排名 ⭐ v3.4
|
||||
5. `ashtakavarga` 计算八分法 → SAV评分+宫位吉凶 ⭐ v3.4
|
||||
6. `varga --d9` 计算 Navamsa 分盘验证
|
||||
7. `transit` 查询当月过境 → 配合 dasha 做推运分析
|
||||
8. `predict` 事件预测(EventPredictionModel规则引擎) ⭐ v3.4
|
||||
9. `celebrity` 查找相似案例做对比验证
|
||||
10. `memory --action store` 保存分析结论供后续引用 ⭐ v3.4
|
||||
6. `varga-full --divisions D9,D60` 计算精确分盘(含度数+尊严) ⭐ v3.7
|
||||
7. `aspects` 计算精确相位(度数级Drishti) ⭐ v3.7
|
||||
8. `jaimini --mode all` 计算Chara Karaka + Dasha + Karakamsha ⭐ v3.7
|
||||
9. `nakshatra-adv --mode all` 计算Tara Bala + Sub-Lord ⭐ v3.7
|
||||
10. `argala` 计算门闩干预分析 ⭐ v3.7
|
||||
11. `transit` 查询当月过境 → 配合 dasha 做推运分析
|
||||
12. `tajika --age 33` 计算年运盘(Muntha+Tri-Pataka) ⭐ v3.7
|
||||
13. `predict` 事件预测(EventPredictionModel规则引擎) ⭐ v3.4
|
||||
14. `celebrity` 查找相似案例做对比验证
|
||||
15. 合盘场景:`synastry --moon1 ... --moon2 ...` 计算Ashta Koota 36分制 ⭐ v3.7
|
||||
16. `memory --action store` 保存分析结论供后续引用 ⭐ v3.4
|
||||
|
||||
## 使用方法
|
||||
|
||||
@@ -376,7 +389,7 @@ $PYTHON $SCRIPT <子命令> [参数]
|
||||
|
||||
## 更新记录
|
||||
|
||||
详见 `CHANGELOG.md`。当前版本:v3.3.0。
|
||||
详见 `CHANGELOG.md`。当前版本:v3.7.0。
|
||||
|
||||
## 参考资料
|
||||
|
||||
@@ -511,6 +524,6 @@ $PYTHON $SCRIPT <子命令> [参数]
|
||||
|
||||
---
|
||||
|
||||
**版本**:3.3.0
|
||||
**版本**:3.7.0
|
||||
**创建日期**:2026-04-20
|
||||
**最后更新**:2026-04-24(v3.3.0 整合Kimi训练手册精华:排盘软件与Ayanamsa指南+Shodasavarga十六分盘体系+替代推运系统+条件Dasha系统+古典文献翻译指南+专业发展路径)
|
||||
**最后更新**:2026-04-25(v3.7.0 新增7大计算模块:BPHS十六分盘精确计算+度数精确相位+Jaimini完整系统+高级Nakshatra分析+Argala门闩+Tajika年运盘+合盘分析,引擎子命令14→21)
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Argala(门闩)行星干预模块 v1.0
|
||||
Parashara体系的行星影响力锁定机制
|
||||
|
||||
Argala = "门闩/木栓",指一颗行星通过特定宫位对另一颗行星产生
|
||||
不可阻挡的干预影响。这是判断行星力量和结果表达的关键技法。
|
||||
|
||||
规则:
|
||||
- 主Argala: 2/4/11宫位产生正面干预
|
||||
- 副Argala: 5/8宫位(从第2宫起算)产生正面干预
|
||||
- Virodha Argala: 12/10/3宫位产生反向阻止
|
||||
- 更强Argala: 多颗行星在同一Argala位置则力量增强
|
||||
"""
|
||||
from typing import Dict, List
|
||||
|
||||
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
|
||||
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
||||
SIGN_LORDS = {'Aries':'Mars','Taurus':'Venus','Gemini':'Mercury','Cancer':'Moon',
|
||||
'Leo':'Sun','Virgo':'Mercury','Libra':'Venus','Scorpio':'Mars',
|
||||
'Sagittarius':'Jupiter','Capricorn':'Saturn','Aquarius':'Saturn','Pisces':'Jupiter'}
|
||||
|
||||
BENEFICS = ['Jupiter', 'Venus', 'Moon']
|
||||
MALEFICS = ['Saturn', 'Mars', 'Sun', 'Rahu', 'Ketu']
|
||||
|
||||
|
||||
def calc_argala(planet_sign_indices: Dict[str, int], asc_sign_idx: int) -> Dict:
|
||||
"""
|
||||
计算所有行星的Argala和Virodha Argala
|
||||
|
||||
参数:
|
||||
planet_sign_indices: {'Sun': 0, 'Moon': 3, ...} 行星所在星座索引
|
||||
asc_sign_idx: 上升星座索引
|
||||
|
||||
返回: {
|
||||
planet_name: {
|
||||
'house': 宫位,
|
||||
'argala_from': [对哪些宫位有Argala],
|
||||
'argala_to': [被哪些行星Argala],
|
||||
'virodha_from': [被哪些行星阻止],
|
||||
'net_argala': 净Argala力量评估,
|
||||
}
|
||||
}
|
||||
"""
|
||||
# 计算各行星宫位
|
||||
houses = {}
|
||||
for pname, si in planet_sign_indices.items():
|
||||
h = ((si - asc_sign_idx) % 12) + 1
|
||||
houses[pname] = h
|
||||
|
||||
# 主Argala位置(从目标行星宫位起算)
|
||||
# 2宫=财富Argala, 4宫=幸福Argala, 11宫=收益Argala
|
||||
MAIN_ARGALA = [2, 4, 11]
|
||||
# 副Argala位置(特殊条件:需要无其他行星在相应Virodha位置)
|
||||
SUB_ARGALA = [5, 8] # 第5宫=权力Argala(当2宫无Virodha), 第8宫(当4宫无Virodha)
|
||||
# Virodha Argala位置(反向阻止)
|
||||
VIRODHA = {2: 12, 4: 10, 11: 3, 5: 9, 8: 2}
|
||||
|
||||
results = {}
|
||||
|
||||
for target_p, target_h in houses.items():
|
||||
argala_on_target = [] # 作用于此行星的Argala
|
||||
virodha_on_target = [] # 作用于此行星的Virodha
|
||||
argala_by_target = [] # 此行星作用于其他位置的Argala
|
||||
|
||||
# 检查哪些行星对此行星有Argala
|
||||
for source_p, source_h in houses.items():
|
||||
if source_p == target_p:
|
||||
continue
|
||||
rel = ((source_h - target_h) % 12) + 1
|
||||
|
||||
# 主Argala检查
|
||||
if rel in MAIN_ARGALA:
|
||||
nature = 'benefic' if source_p in BENEFICS else 'malefic'
|
||||
strength = 'strong' if _is_strong_argala(source_p, rel) else 'normal'
|
||||
argala_on_target.append({
|
||||
'source': source_p, 'house_from': rel,
|
||||
'type': 'main', 'nature': nature, 'strength': strength,
|
||||
'effect': _argala_effect(rel, nature),
|
||||
})
|
||||
|
||||
# 副Argala检查
|
||||
elif rel in SUB_ARGALA:
|
||||
nature = 'benefic' if source_p in BENEFICS else 'malefic'
|
||||
argala_on_target.append({
|
||||
'source': source_p, 'house_from': rel,
|
||||
'type': 'sub', 'nature': nature, 'strength': 'conditional',
|
||||
'effect': _argala_effect(rel, nature),
|
||||
})
|
||||
|
||||
# Virodha检查
|
||||
for a_house, v_house in VIRODHA.items():
|
||||
if rel == v_house:
|
||||
nature = 'benefic' if source_p in BENEFICS else 'malefic'
|
||||
virodha_on_target.append({
|
||||
'source': source_p, 'house_from': rel,
|
||||
'blocks_argala_from': a_house,
|
||||
'nature': nature,
|
||||
})
|
||||
|
||||
# 此行星对其他位置产生的Argala
|
||||
for rel_house in MAIN_ARGALA:
|
||||
target_house = ((target_h - 1 + rel_house - 1) % 12) + 1
|
||||
planets_there = [p for p, h in houses.items() if h == target_house]
|
||||
if planets_there:
|
||||
argala_by_target.append({
|
||||
'argala_type': f'{rel_house}宫Argala',
|
||||
'target_house': target_house,
|
||||
'affects': planets_there,
|
||||
'effect': _argala_effect(rel_house, 'benefic' if target_p in BENEFICS else 'malefic'),
|
||||
})
|
||||
|
||||
# 净Argala评估
|
||||
benefic_argala = sum(1 for a in argala_on_target if a['nature'] == 'benefic')
|
||||
malefic_argala = sum(1 for a in argala_on_target if a['nature'] == 'malefic')
|
||||
benefic_virodha = sum(1 for v in virodha_on_target if v['nature'] == 'benefic')
|
||||
malefic_virodha = sum(1 for v in virodha_on_target if v['nature'] == 'malefic')
|
||||
|
||||
net = (benefic_argala - malefic_virodha) - (malefic_argala - benefic_virodha)
|
||||
|
||||
results[target_p] = {
|
||||
'house': target_h,
|
||||
'argala_on_this': argala_on_target,
|
||||
'virodha_on_this': virodha_on_target,
|
||||
'argala_by_this': argala_by_target,
|
||||
'net_score': net,
|
||||
'net_assessment': 'strongly_supported' if net >= 2 else 'supported' if net >= 1
|
||||
else 'blocked' if net <= -2 else 'neutral',
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def _is_strong_argala(planet, house):
|
||||
"""判断Argala是否特别强(有2+行星在同一位置)"""
|
||||
return False # 需要宫位行星数信息,简化返回
|
||||
|
||||
|
||||
def _argala_effect(house, nature):
|
||||
"""Argala效果描述"""
|
||||
effects = {
|
||||
2: {'benefic': '财富和资源流入', 'malefic': '财务压力和资源消耗'},
|
||||
4: {'benefic': '幸福感、住所和内心平静增强', 'malefic': '家庭不和、住所问题'},
|
||||
11: {'benefic': '收益、愿望实现和社会认可', 'malefic': '损失、社会障碍'},
|
||||
5: {'benefic': '智慧、权力和创造力增强', 'malefic': '智力困扰、决策失误'},
|
||||
8: {'benefic': '隐藏资源和转化力量', 'malefic': '隐藏障碍和突发危机'},
|
||||
}
|
||||
return effects.get(house, {}).get(nature, '一般性影响')
|
||||
@@ -0,0 +1,204 @@
|
||||
#!/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, # 松散相位(最弱)
|
||||
}
|
||||
|
||||
# 特殊相位规则(从行星所在宫位算起)
|
||||
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
|
||||
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Jaimini占星体系模块 v1.0
|
||||
Parashara传承中的Jaimini子系统
|
||||
|
||||
支持:
|
||||
- Chara Karaka: 7/8个功能指示星(按度数排序)
|
||||
- Chara Dasha: 基于星座的大运系统
|
||||
- Karakamsha: DK在Navamsa中的上升(灵魂方向)
|
||||
- Jaimini Sutras关键规则
|
||||
"""
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
import math
|
||||
|
||||
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
|
||||
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
||||
SIGN_LORDS = {'Aries':'Mars','Taurus':'Venus','Gemini':'Mercury','Cancer':'Moon',
|
||||
'Leo':'Sun','Virgo':'Mercury','Libra':'Venus','Scorpio':'Mars',
|
||||
'Sagittarius':'Jupiter','Capricorn':'Saturn','Aquarius':'Saturn','Pisces':'Jupiter'}
|
||||
|
||||
# Chara Karaka 定义(7星制,排除Rahu)
|
||||
KARAKA_7 = {
|
||||
1: 'Atmakaraka', # AK - 灵魂指示星(度数最高)
|
||||
2: 'Amatyakaraka', # AmK - 事业/顾问
|
||||
3: 'Bhratrikaraka', # BK - 兄弟/勇气
|
||||
4: 'Matrikaraka', # MK - 母亲
|
||||
5: 'Putrakaraka', # PK - 子女
|
||||
6: 'Gnatikaraka', # GK - 敌人/障碍
|
||||
7: 'Darakaraka', # DK - 配偶(度数最低)
|
||||
}
|
||||
|
||||
# 8星制(含Rahu,用绝对度数)
|
||||
KARAKA_8 = {
|
||||
1: 'Atmakaraka', 2: 'Amatyakaraka', 3: 'Bhratrikaraka', 4: 'Matrikaraka',
|
||||
5: 'Putrakaraka', 6: 'Gnatikaraka', 7: 'Darakaraka', 8: 'Pitrukaraka',
|
||||
}
|
||||
|
||||
KARAKA_CN = {
|
||||
'Atmakaraka': '灵魂星AK', 'Amatyakaraka': '事业星AmK',
|
||||
'Bhratrikaraka': '兄弟星BK', 'Matrikaraka': '母亲星MK',
|
||||
'Putrakaraka': '子女星PK', 'Gnatikaraka': '障碍星GK',
|
||||
'Darakaraka': '配偶星DK', 'Pitrukaraka': '父亲星PiK',
|
||||
}
|
||||
|
||||
KARAKA_DOMAINS = {
|
||||
'Atmakaraka': '灵魂使命、核心自我、人生最高目标',
|
||||
'Amatyakaraka': '事业方向、主要谋士、权力代理',
|
||||
'Bhratrikaraka': '兄弟姐妹、勇气、冒险精神',
|
||||
'Matrikaraka': '母亲、家庭根基、情感安全感',
|
||||
'Putrakaraka': '子女、创造力、学生、智能成果',
|
||||
'Gnatikaraka': '竞争对手、疾病、障碍、转化力量',
|
||||
'Darakaraka': '配偶特质、伴侣关系、婚姻质量',
|
||||
'Pitrukaraka': '父亲、祖先业力、传统传承',
|
||||
}
|
||||
|
||||
|
||||
def calc_chara_karaka_7(planet_degrees: Dict[str, float]) -> Dict:
|
||||
"""
|
||||
计算7星制Chara Karaka(度数最高→AK,最低→DK)
|
||||
|
||||
参数: planet_degrees = {'Sun': 12.5, 'Moon': 8.3, ...}
|
||||
每个行星在星座内的度数(0-30)
|
||||
|
||||
返回: {karaka_name: {'planet': str, 'degree': float, 'domain': str}}
|
||||
"""
|
||||
# 排除Rahu和Ketu
|
||||
exclude = {'Rahu', 'Ketu'}
|
||||
planets = {k: v for k, v in planet_degrees.items() if k not in exclude}
|
||||
|
||||
# 按度数降序排列(度数最高的=AK)
|
||||
sorted_planets = sorted(planets.items(), key=lambda x: x[1], reverse=True)
|
||||
|
||||
results = {}
|
||||
for rank, (pname, deg) in enumerate(sorted_planets, 1):
|
||||
if rank > 7:
|
||||
break
|
||||
karaka = KARAKA_7[rank]
|
||||
results[karaka] = {
|
||||
'planet': pname,
|
||||
'degree_in_sign': round(deg, 4),
|
||||
'rank': rank,
|
||||
'domain': KARAKA_DOMAINS.get(karaka, ''),
|
||||
'cn_name': KARAKA_CN.get(karaka, karaka),
|
||||
}
|
||||
|
||||
# 额外分析
|
||||
ak = results.get('Atmakaraka', {})
|
||||
dk = results.get('Darakaraka', {})
|
||||
|
||||
return {
|
||||
'karaka_table': results,
|
||||
'summary': {
|
||||
'AK': f"{ak.get('planet','?')} ({ak.get('degree_in_sign',0):.1f}°)",
|
||||
'DK': f"{dk.get('planet','?')} ({dk.get('degree_in_sign',0):.1f}°)",
|
||||
'AK_domain': ak.get('domain', ''),
|
||||
'DK_domain': dk.get('domain', ''),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def calc_chara_karaka_8(planet_degrees: Dict[str, float]) -> Dict:
|
||||
"""
|
||||
计算8星制Chara Karaka(含Rahu,使用30-度数来处理Rahu逆行)
|
||||
"""
|
||||
planets = {}
|
||||
for pname, deg in planet_degrees.items():
|
||||
if pname == 'Ketu':
|
||||
continue
|
||||
if pname == 'Rahu':
|
||||
# Rahu用反向度数
|
||||
planets[pname] = (30 - deg) % 30
|
||||
else:
|
||||
planets[pname] = deg
|
||||
|
||||
sorted_planets = sorted(planets.items(), key=lambda x: x[1], reverse=True)
|
||||
|
||||
results = {}
|
||||
for rank, (pname, deg) in enumerate(sorted_planets, 1):
|
||||
if rank > 8:
|
||||
break
|
||||
karaka = KARAKA_8[rank]
|
||||
results[karaka] = {
|
||||
'planet': pname,
|
||||
'degree_in_sign': round(deg, 4),
|
||||
'rank': rank,
|
||||
'domain': KARAKA_DOMAINS.get(karaka, ''),
|
||||
'cn_name': KARAKA_CN.get(karaka, karaka),
|
||||
}
|
||||
|
||||
return {'karaka_table_8': results}
|
||||
|
||||
|
||||
def calc_chara_dasha(asc_sign_idx: int,
|
||||
planet_longitudes: Dict[str, float],
|
||||
birth_year: int, birth_month: int) -> Dict:
|
||||
"""
|
||||
Chara Dasha计算(基于星座的大运系统)
|
||||
|
||||
规则:
|
||||
- 从上升星座开始
|
||||
- 奇数星座(Aries, Gemini...):正向顺序
|
||||
- 偶数星座(Taurus, Cancer...):反向顺序
|
||||
- 每个大运长度 = 12 - 该星座内的行星数量(用特定规则)
|
||||
- 标准版:每个大运固定1-12年
|
||||
"""
|
||||
# 确定顺序方向
|
||||
is_odd = asc_sign_idx % 2 == 0
|
||||
direction = 1 if is_odd else -1
|
||||
|
||||
# 生成大运序列
|
||||
dasha_sequence = []
|
||||
current = asc_sign_idx
|
||||
|
||||
# 标准Chara Dasha: 每个星座1年,按正/反向排列
|
||||
for i in range(12):
|
||||
sign_idx = (current + direction * i) % 12
|
||||
sign_name = SIGNS[sign_idx]
|
||||
lord = SIGN_LORDS[sign_name]
|
||||
|
||||
# 大运长度计算(简化版:基于星座的默认年数)
|
||||
# 标准法:大运长度 = 基于该星座中行星的Karakamsa计算
|
||||
# 简化法:每个大运1年
|
||||
duration = _chara_dasha_duration(sign_idx, planet_longitudes)
|
||||
|
||||
dasha_sequence.append({
|
||||
'sign': sign_name,
|
||||
'sign_idx': sign_idx,
|
||||
'lord': lord,
|
||||
'duration_years': duration,
|
||||
'order': i + 1,
|
||||
})
|
||||
|
||||
# 计算日期
|
||||
total_years = sum(d['duration_years'] for d in dasha_sequence)
|
||||
current_year = birth_year
|
||||
current_month = birth_month
|
||||
|
||||
for d in dasha_sequence:
|
||||
d['start_date'] = f"{current_year}-{current_month:02d}"
|
||||
end_month = current_month + int(d['duration_years'] * 12)
|
||||
end_year = current_year + end_month // 12
|
||||
end_month = end_month % 12
|
||||
if end_month == 0:
|
||||
end_month = 12
|
||||
end_year -= 1
|
||||
d['end_date'] = f"{end_year}-{end_month:02d}"
|
||||
current_year = end_year
|
||||
current_month = end_month + 1
|
||||
if current_month > 12:
|
||||
current_month = 1
|
||||
current_year += 1
|
||||
|
||||
return {
|
||||
'ascendant': SIGNS[asc_sign_idx],
|
||||
'direction': 'forward' if is_odd else 'backward',
|
||||
'dasha_sequence': dasha_sequence,
|
||||
'total_years': total_years,
|
||||
}
|
||||
|
||||
|
||||
def _chara_dasha_duration(sign_idx, planet_lons):
|
||||
"""计算Chara Dasha单个大运的年数"""
|
||||
# 标准方法:12 - 落入该星座的行星数量(最少1年,最多12年)
|
||||
count = 0
|
||||
for pname, lon in planet_lons.items():
|
||||
if pname in ('Rahu', 'Ketu'):
|
||||
continue
|
||||
p_sign = int(lon / 30) % 12
|
||||
if p_sign == sign_idx:
|
||||
count += 1
|
||||
return max(1, 12 - count)
|
||||
|
||||
|
||||
def calc_karakamsha(dk_sign_in_d9: str, dk_degree_in_d9: float) -> Dict:
|
||||
"""
|
||||
Karakamsha分析:DK在D9中的位置作为"灵魂上升"
|
||||
这是Jaimini体系中判断人生终极方向的关键技法
|
||||
|
||||
参数:
|
||||
dk_sign_in_d9: DK在D9中的星座
|
||||
dk_degree_in_d9: DK在D9中的度数
|
||||
"""
|
||||
sign_idx = SIGNS.index(dk_sign_in_d9) if dk_sign_in_d9 in SIGNS else 0
|
||||
lord = SIGN_LORDS.get(dk_sign_in_d9, '')
|
||||
|
||||
# Karakamsha Lagna = DK在D9中的位置
|
||||
# 从这个位置看12宫的布局,分析灵魂方向
|
||||
interpretations = _karakamsha_interpretations(dk_sign_in_d9, lord)
|
||||
|
||||
return {
|
||||
'karakamsha_sign': dk_sign_in_d9,
|
||||
'karakamsha_degree': dk_degree_in_d9,
|
||||
'karakamsha_lord': lord,
|
||||
'soul_direction': interpretations,
|
||||
}
|
||||
|
||||
|
||||
def _karakamsha_interpretations(sign, lord):
|
||||
"""Karakamsha的灵魂方向解读"""
|
||||
directions = {
|
||||
'Aries': '灵魂追求独立、开拓、成为先驱',
|
||||
'Taurus': '灵魂追求稳定、物质安全感、感官和谐',
|
||||
'Gemini': '灵魂追求知识、沟通、多元体验',
|
||||
'Cancer': '灵魂追求情感连接、家庭、滋养他人',
|
||||
'Leo': '灵魂追求创造力、领导力、自我表达',
|
||||
'Virgo': '灵魂追求服务、完善、分析能力',
|
||||
'Libra': '灵魂追求平衡、关系和谐、美学',
|
||||
'Scorpio': '灵魂追求转化、深层真相、神秘学',
|
||||
'Sagittarius': '灵魂追求真理、哲学、智慧传播',
|
||||
'Capricorn': '灵魂追求成就、结构、社会贡献',
|
||||
'Aquarius': '灵魂追求革新、人道主义、群体觉醒',
|
||||
'Pisces': '灵魂追求灵性、超越、无条件的爱',
|
||||
}
|
||||
lord_meanings = {
|
||||
'Sun': '通过权威、创造力和自我实现达成',
|
||||
'Moon': '通过情感智慧、直觉和公众影响力达成',
|
||||
'Mars': '通过行动力、勇气和技术能力达成',
|
||||
'Mercury': '通过智慧、沟通和学习能力达成',
|
||||
'Jupiter': '通过智慧、教导和灵性成长达成',
|
||||
'Venus': '通过美学、关系和创造力达成',
|
||||
'Saturn': '通过耐力、自律和长期承诺达成',
|
||||
}
|
||||
return {
|
||||
'sign_direction': directions.get(sign, ''),
|
||||
'lord_method': lord_meanings.get(lord, ''),
|
||||
}
|
||||
+262
-3
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
印度占星统一引擎 v3.6.0 (Jyotish Unified Engine)
|
||||
印度占星统一引擎 v3.7.0 (Jyotish Unified Engine)
|
||||
整合所有计算能力为单一CLI入口,供Skill调用
|
||||
|
||||
子命令:
|
||||
@@ -10,6 +10,13 @@
|
||||
yoga Yoga格局识别
|
||||
predict 三层验证法事件预测(优先EventPredictionModel规则引擎)
|
||||
varga 分盘计算(D9/D10)
|
||||
varga-full BPHS十六分盘完整计算(D2-D60)(v3.7新增)
|
||||
aspects 度数精确相位系统(v3.7新增)
|
||||
jaimini Jaimini系统(Chara Karaka/Chara Dasha/Karakamsha)(v3.7新增)
|
||||
nakshatra-adv 高级Nakshatra分析(Tara Bala/Sub-Lord/兼容性)(v3.7新增)
|
||||
argala Argala门闩系统(v3.7新增)
|
||||
tajika Tajika/Varshaphala年运盘(v3.7新增)
|
||||
synastry 合盘分析(Ashta Koota 36分制+Mangal Dosha)(v3.7新增)
|
||||
celebrity 名人案例查询(15,807条数据+SQLite验证库)
|
||||
db-stats 验证数据库统计
|
||||
transit 行星过境查询
|
||||
@@ -1043,11 +1050,220 @@ def cmd_report(args):
|
||||
sys.argv = old_argv
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 15. BPHS十六分盘完整计算(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_varga_full(args):
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz)
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from varga import calc_all_vargas
|
||||
except ImportError as e:
|
||||
return {"error": f"varga模块导入失败: {e}"}
|
||||
planets = chart.get('planets', {})
|
||||
planet_lons = {pn: pd['degree'] for pn, pd in planets.items() if isinstance(pd, dict) and 'degree' in pd}
|
||||
asc_deg = chart.get('ascendant', {}).get('degree', 0)
|
||||
divisions = [int(d.strip().replace('D','')) for d in args.divisions.split(',')] if args.divisions else None
|
||||
return calc_all_vargas(planet_lons, asc_deg, divisions)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 16. 度数精确相位系统(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_aspects(args):
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz)
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from aspects import calc_all_aspects
|
||||
except ImportError as e:
|
||||
return {"error": f"aspects模块导入失败: {e}"}
|
||||
planets = chart.get('planets', {})
|
||||
planet_lons = {}
|
||||
for pn, pd in planets.items():
|
||||
if isinstance(pd, dict) and 'degree' in pd:
|
||||
planet_lons[pn] = pd['degree']
|
||||
asc_deg = chart.get('ascendant', {}).get('degree', 0)
|
||||
return calc_all_aspects(planet_lons, asc_deg)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 17. Jaimini系统(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_jaimini(args):
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz)
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from jaimini import calc_chara_karaka_7, calc_chara_karaka_8, calc_chara_dasha, calc_karakamsha
|
||||
from varga import calc_varga
|
||||
except ImportError as e:
|
||||
return {"error": f"jaimini模块导入失败: {e}"}
|
||||
planets = chart.get('planets', {})
|
||||
planet_lons = {}
|
||||
for pn, pd in planets.items():
|
||||
if isinstance(pd, dict) and 'degree' in pd:
|
||||
planet_lons[pn] = pd['degree']
|
||||
asc_deg = chart.get('ascendant', {}).get('degree', 0)
|
||||
|
||||
result = {}
|
||||
# Chara Karaka
|
||||
mode = args.mode or 'all'
|
||||
if mode in ('all', 'karaka'):
|
||||
result['chara_karaka_7'] = calc_chara_karaka_7(planet_lons)
|
||||
result['chara_karaka_8'] = calc_chara_karaka_8(planet_lons)
|
||||
if mode in ('all', 'dasha'):
|
||||
result['chara_dasha'] = calc_chara_dasha(asc_idx, planet_lons, args.year, args.month)
|
||||
if mode in ('all', 'karakamsha'):
|
||||
# DK的D9位置
|
||||
ck7 = calc_chara_karaka_7(planet_lons)
|
||||
dk_name = ck7.get('DK', {}).get('planet', 'Moon')
|
||||
dk_lon = planet_lons.get(dk_name, 0)
|
||||
dk_d9 = calc_varga(dk_lon, 9)
|
||||
result['karakamsha'] = calc_karakamsha(dk_d9.get('sign', 'Aries'), dk_d9.get('degree_in_sign', 0))
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 18. 高级Nakshatra分析(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_nakshatra_adv(args):
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz)
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from nakshatra_advanced import find_nakshatra, calc_all_tara_balas, calc_sub_lord, nakshatra_compatibility
|
||||
except ImportError as e:
|
||||
return {"error": f"nakshatra_advanced模块导入失败: {e}"}
|
||||
planets = chart.get('planets', {})
|
||||
planet_lons = {}
|
||||
for pn, pd in planets.items():
|
||||
if isinstance(pd, dict) and 'degree' in pd:
|
||||
planet_lons[pn] = pd['degree']
|
||||
|
||||
result = {'planets': {}}
|
||||
mode = args.mode or 'all'
|
||||
|
||||
if mode in ('all', 'detail'):
|
||||
for pn, lon in planet_lons.items():
|
||||
result['planets'][pn] = find_nakshatra(lon)
|
||||
|
||||
if mode in ('all', 'tara'):
|
||||
moon_lon = planet_lons.get('Moon', 0)
|
||||
moon_nak_idx = int(moon_lon / (360/27)) % 27
|
||||
result['tara_bala'] = calc_all_tara_balas(moon_nak_idx, planet_lons)
|
||||
|
||||
if mode in ('all', 'sublord'):
|
||||
result['sub_lords'] = {pn: calc_sub_lord(lon) for pn, lon in planet_lons.items()}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 19. Argala门闩系统(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_argala(args):
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz)
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from argala import calc_argala
|
||||
except ImportError as e:
|
||||
return {"error": f"argala模块导入失败: {e}"}
|
||||
planets = chart.get('planets', {})
|
||||
# 构建宫位到行星的映射 - argala需要sign_indices
|
||||
planet_sign_indices = {}
|
||||
for pn, pd in planets.items():
|
||||
if isinstance(pd, dict) and 'sign' in pd:
|
||||
si = SIGNS.index(pd['sign']) if pd['sign'] in SIGNS else 0
|
||||
planet_sign_indices[pn] = si
|
||||
return calc_argala(planet_sign_indices, asc_idx)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 20. Tajika/Varshaphala年运盘(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_tajika(args):
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz)
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from tajika import calc_muntha, calc_year_lord, calc_mudda_dasha, calc_tri_pataka
|
||||
except ImportError as e:
|
||||
return {"error": f"tajika模块导入失败: {e}"}
|
||||
planets = chart.get('planets', {})
|
||||
planet_lons = {}
|
||||
for pn, pd in planets.items():
|
||||
if isinstance(pd, dict) and 'degree' in pd:
|
||||
planet_lons[pn] = pd['degree']
|
||||
asc_deg = chart.get('ascendant', {}).get('degree', 0)
|
||||
asc_si = int(asc_deg / 30) % 12 # sign index
|
||||
age = args.age
|
||||
if age is None:
|
||||
return {"error": "请提供 --age 参数(当前年龄)"}
|
||||
|
||||
result = {}
|
||||
mode = args.mode or 'all'
|
||||
if mode in ('all', 'muntha'):
|
||||
result['muntha'] = calc_muntha(asc_si, age)
|
||||
if mode in ('all', 'yearlord'):
|
||||
result['year_lord'] = calc_year_lord(asc_si, age)
|
||||
if mode in ('all', 'mudda'):
|
||||
# 需要先获取 varsha_lord
|
||||
yl = calc_year_lord(asc_si, age)
|
||||
varsha_lord = yl.get('year_lord', 'Jupiter')
|
||||
result['mudda_dasha'] = calc_mudda_dasha(asc_si, varsha_lord, args.month)
|
||||
if mode in ('all', 'tripataka'):
|
||||
yl = calc_year_lord(asc_si, age)
|
||||
varsha_lord = yl.get('year_lord', 'Jupiter')
|
||||
muntha_si = (asc_si + age) % 12
|
||||
result['tri_pataka'] = calc_tri_pataka(planet_lons, varsha_lord, muntha_si)
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 21. 合盘分析(v3.7新增)
|
||||
# ============================================================================
|
||||
def cmd_synastry(args):
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from synastry import calc_synastry
|
||||
except ImportError as e:
|
||||
return {"error": f"synastry模块导入失败: {e}"}
|
||||
# 构建两人数据
|
||||
p1 = {'moon_lon': args.moon1, 'gender': args.gender1 or 'M'}
|
||||
p2 = {'moon_lon': args.moon2, 'gender': args.gender2 or 'F'}
|
||||
if args.mars1 is not None: p1['mars_lon'] = args.mars1
|
||||
if args.mars2 is not None: p2['mars_lon'] = args.mars2
|
||||
if args.asc1 is not None: p1['asc_lon'] = args.asc1
|
||||
if args.asc2 is not None: p2['asc_lon'] = args.asc2
|
||||
return calc_synastry(p1, p2)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# CLI入口
|
||||
# ============================================================================
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='印度占星统一引擎 v3.6.0', formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser = argparse.ArgumentParser(description='印度占星统一引擎 v3.7.0', formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
sub = parser.add_subparsers(dest='command', help='子命令')
|
||||
|
||||
# 1. chart
|
||||
@@ -1132,6 +1348,46 @@ def main():
|
||||
p.add_argument('--lang', default='cn', choices=['cn', 'en'], help='语言 (默认cn)')
|
||||
p.add_argument('--output', default=None, help='输出HTML路径')
|
||||
|
||||
# 15. varga-full (v3.7新增)
|
||||
p = sub.add_parser('varga-full', help='BPHS十六分盘完整计算')
|
||||
_add_chart_args(p)
|
||||
p.add_argument('--divisions', default=None, help='指定分盘,逗号分隔(如 D2,D9,D60),空=全部')
|
||||
|
||||
# 16. aspects (v3.7新增)
|
||||
p = sub.add_parser('aspects', help='度数精确相位系统')
|
||||
_add_chart_args(p)
|
||||
|
||||
# 17. jaimini (v3.7新增)
|
||||
p = sub.add_parser('jaimini', help='Jaimini系统(Chara Karaka/Dasha/Karakamsha)')
|
||||
_add_chart_args(p)
|
||||
p.add_argument('--mode', default='all', choices=['all','karaka','dasha','karakamsha'], help='分析模式')
|
||||
|
||||
# 18. nakshatra-adv (v3.7新增)
|
||||
p = sub.add_parser('nakshatra-adv', help='高级Nakshatra分析')
|
||||
_add_chart_args(p)
|
||||
p.add_argument('--mode', default='all', choices=['all','detail','tara','sublord'], help='分析模式')
|
||||
|
||||
# 19. argala (v3.7新增)
|
||||
p = sub.add_parser('argala', help='Argala门闩系统')
|
||||
_add_chart_args(p)
|
||||
|
||||
# 20. tajika (v3.7新增)
|
||||
p = sub.add_parser('tajika', help='Tajika/Varshaphala年运盘')
|
||||
_add_chart_args(p)
|
||||
p.add_argument('--age', type=int, required=True, help='当前年龄')
|
||||
p.add_argument('--mode', default='all', choices=['all','muntha','yearlord','mudda','tripataka'], help='分析模式')
|
||||
|
||||
# 21. synastry (v3.7新增)
|
||||
p = sub.add_parser('synastry', help='合盘分析(Ashta Koota 36分制)')
|
||||
p.add_argument('--moon1', type=float, required=True, help='Person1月亮黄经')
|
||||
p.add_argument('--moon2', type=float, required=True, help='Person2月亮黄经')
|
||||
p.add_argument('--mars1', type=float, default=None, help='Person1火星黄经')
|
||||
p.add_argument('--mars2', type=float, default=None, help='Person2火星黄经')
|
||||
p.add_argument('--asc1', type=float, default=None, help='Person1上升黄经')
|
||||
p.add_argument('--asc2', type=float, default=None, help='Person2上升黄经')
|
||||
p.add_argument('--gender1', default='M', help='Person1性别')
|
||||
p.add_argument('--gender2', default='F', help='Person2性别')
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.command:
|
||||
parser.print_help(); sys.exit(1)
|
||||
@@ -1139,7 +1395,10 @@ def main():
|
||||
cmds = {'chart': cmd_chart, 'dasha': cmd_dasha, 'yoga': cmd_yoga, 'predict': cmd_predict,
|
||||
'varga': cmd_varga, 'celebrity': cmd_celebrity, 'db-stats': cmd_db_stats, 'transit': cmd_transit,
|
||||
'shadbala': cmd_shadbala, 'ashtakavarga': cmd_ashtakavarga, 'memory': cmd_memory,
|
||||
'validate': cmd_validate, 'audit': cmd_audit, 'report': cmd_report}
|
||||
'validate': cmd_validate, 'audit': cmd_audit, 'report': cmd_report,
|
||||
'varga-full': cmd_varga_full, 'aspects': cmd_aspects, 'jaimini': cmd_jaimini,
|
||||
'nakshatra-adv': cmd_nakshatra_adv, 'argala': cmd_argala, 'tajika': cmd_tajika,
|
||||
'synastry': cmd_synastry}
|
||||
result = cmds[args.command](args)
|
||||
output_json(result)
|
||||
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
高级星宿分析模块 v1.0
|
||||
Nakshatra深度分析系统
|
||||
|
||||
支持:
|
||||
- Tara Bala(星宿力量匹配)
|
||||
- Sub-Lord体系(KP占星)
|
||||
- 精确Vimshottari起始点计算
|
||||
- Nakshatra兼容性分析
|
||||
- Navatara(9星宿组)分类
|
||||
"""
|
||||
from typing import Dict, List, Tuple
|
||||
import math
|
||||
|
||||
NAK_LIST = [
|
||||
("Ashwini","Ketu",7),("Bharani","Venus",20),("Krittika","Sun",6),
|
||||
("Rohini","Moon",10),("Mrigashira","Mars",7),("Ardra","Rahu",18),
|
||||
("Punarvasu","Jupiter",16),("Pushya","Saturn",19),("Ashlesha","Mercury",17),
|
||||
("Magha","Ketu",7),("Purva Phalguni","Venus",20),("Uttara Phalguni","Sun",6),
|
||||
("Hasta","Moon",10),("Chitra","Mars",7),("Swati","Rahu",18),
|
||||
("Vishakha","Jupiter",16),("Anuradha","Saturn",19),("Jyeshtha","Mercury",17),
|
||||
("Mula","Ketu",7),("Purva Ashadha","Venus",20),("Uttara Ashadha","Sun",6),
|
||||
("Shravana","Moon",10),("Dhanishta","Mars",7),("Shatabhisha","Rahu",18),
|
||||
("Purva Bhadrapada","Jupiter",16),("Uttara Bhadrapada","Saturn",19),("Revati","Mercury",17),
|
||||
]
|
||||
NAK_NAMES = [n[0] for n in NAK_LIST]
|
||||
NAK_LORDS = [n[1] for n in NAK_LIST]
|
||||
NAK_YEARS = [n[2] for n in NAK_LIST]
|
||||
|
||||
# Navatara分组(从月亮星宿开始的9个星宿循环)
|
||||
TARA_NAMES = ['Janma(生命)','Sampat(财富)','Vipat(危险)','Kshema(安全)',
|
||||
'Pratyak(障碍)','Sadhana(成就)','Vadha(毁灭)','Mitra(友好)','ParamaMitra(至友)']
|
||||
TARA_CN = {0:'生命Tara',1:'财富Tara',2:'危险Tara',3:'安全Tara',
|
||||
4:'障碍Tara',5:'成就Tara',6:'毁灭Tara',7:'友好Tara',8:'至友Tara'}
|
||||
|
||||
# Nakshatra元素和属性
|
||||
NAK_GANA = { # 气质类型
|
||||
0:'Dev(神圣)',1:'Manushya(人类)',2:'Rakshasa(罗刹)',
|
||||
3:'Dev',4:'Dev',5:'Manushya',6:'Dev',7:'Dev',8:'Rakshasa',
|
||||
9:'Rakshasa',10:'Manushya',11:'Manushya',12:'Dev',13:'Rakshasa',14:'Dev',
|
||||
15:'Rakshasa',16:'Dev',17:'Rakshasa',18:'Rakshasa',19:'Manushya',20:'Manushya',
|
||||
21:'Dev',22:'Rakshasa',23:'Rakshasa',24:'Manushya',25:'Manushya',26:'Dev',
|
||||
}
|
||||
NAK_ELEMENT = {
|
||||
0:'火',1:'土',2:'火',3:'土',4:'土',5:'风',6:'风',7:'水',8:'水',
|
||||
9:'火',10:'土',11:'火',12:'土',13:'火',14:'风',15:'火',16:'水',17:'风',
|
||||
18:'火',19:'水',20:'土',21:'土',22:'风',23:'风',24:'水',25:'火',26:'水',
|
||||
}
|
||||
|
||||
|
||||
def find_nakshatra(longitude: float) -> Dict:
|
||||
"""从恒星黄道经度精确计算Nakshatra"""
|
||||
nak_span = 360.0 / 27 # 每个星宿13.333...°
|
||||
nak_idx = int(longitude / nak_span) % 27
|
||||
nak_start = nak_idx * nak_span
|
||||
deg_in_nak = longitude - nak_start
|
||||
pada_span = nak_span / 4 # 每个Pada 3.333...°
|
||||
pada = int(deg_in_nak / pada_span) + 1
|
||||
deg_in_pada = deg_in_nak - (pada - 1) * pada_span
|
||||
|
||||
return {
|
||||
'nakshatra': NAK_NAMES[nak_idx],
|
||||
'nakshatra_idx': nak_idx,
|
||||
'nakshatra_lord': NAK_LORDS[nak_idx],
|
||||
'dasha_years': NAK_YEARS[nak_idx],
|
||||
'pada': pada,
|
||||
'degree_in_nakshatra': round(deg_in_nak, 4),
|
||||
'degree_in_pada': round(deg_in_pada, 4),
|
||||
'gana': NAK_GANA.get(nak_idx, ''),
|
||||
'element': NAK_ELEMENT.get(nak_idx, ''),
|
||||
}
|
||||
|
||||
|
||||
def calc_tara_bala(moon_nak_idx: int, target_nak_idx: int) -> Dict:
|
||||
"""
|
||||
Tara Bala计算:月亮星宿到目标星宿的9星宿循环关系
|
||||
|
||||
用于判断某个行星/事件星宿与月亮星宿的关系
|
||||
0=Janma(中性), 1=Sampat(吉), 2=Vipat(凶), 3=Kshema(吉),
|
||||
4=Pratyak(凶), 5=Sadhana(吉), 6=Vadha(凶), 7=Mitra(吉), 8=ParamaMitra(大吉)
|
||||
"""
|
||||
distance = (target_nak_idx - moon_nak_idx) % 9
|
||||
tara_name = TARA_NAMES[distance]
|
||||
tara_cn = TARA_CN[distance]
|
||||
|
||||
is_auspicious = distance in (1, 3, 5, 7, 8)
|
||||
is_dangerous = distance in (2, 4, 6)
|
||||
|
||||
return {
|
||||
'tara_index': distance,
|
||||
'tara_name': tara_name,
|
||||
'tara_cn': tara_cn,
|
||||
'is_auspicious': is_auspicious,
|
||||
'is_dangerous': is_dangerous,
|
||||
'quality': 'auspicious' if is_auspicious else 'dangerous' if is_dangerous else 'neutral',
|
||||
'interpretation': _tara_interp(distance),
|
||||
}
|
||||
|
||||
|
||||
def calc_all_tara_balas(moon_nak_idx: int, planet_lons: Dict[str, float]) -> Dict:
|
||||
"""计算所有行星相对于月亮的Tara Bala"""
|
||||
results = {}
|
||||
for pname, lon in planet_lons.items():
|
||||
p_nak = find_nakshatra(lon)
|
||||
tara = calc_tara_bala(moon_nak_idx, p_nak['nakshatra_idx'])
|
||||
results[pname] = {
|
||||
'nakshatra': p_nak['nakshatra'],
|
||||
'tara': tara,
|
||||
}
|
||||
return results
|
||||
|
||||
|
||||
def calc_vimshottari_start(moon_longitude: float) -> Dict:
|
||||
"""
|
||||
精确计算Vimshottari Dasha的起始点
|
||||
|
||||
返回月亮所在星宿的守护星、已用度数比例、剩余年数
|
||||
"""
|
||||
nak = find_nakshatra(moon_longitude)
|
||||
nak_idx = nak['nakshatra_idx']
|
||||
nak_lord = NAK_LORDS[nak_idx]
|
||||
total_years = NAK_YEARS[nak_idx]
|
||||
|
||||
# 已用比例
|
||||
nak_span = 360.0 / 27
|
||||
nak_start = nak_idx * nak_span
|
||||
deg_in_nak = moon_longitude - nak_start
|
||||
used_ratio = deg_in_nak / nak_span
|
||||
remaining_ratio = 1 - used_ratio
|
||||
|
||||
# 第一个Mahadasha的剩余年数
|
||||
first_mahadasha_remaining = total_years * remaining_ratio
|
||||
first_mahadasha_elapsed = total_years * used_ratio
|
||||
|
||||
return {
|
||||
'moon_nakshatra': nak['nakshatra'],
|
||||
'moon_nakshatra_lord': nak_lord,
|
||||
'moon_pada': nak['pada'],
|
||||
'total_dasha_years': total_years,
|
||||
'used_ratio': round(used_ratio, 6),
|
||||
'remaining_ratio': round(remaining_ratio, 6),
|
||||
'first_mahadasha_remaining_years': round(first_mahadasha_remaining, 4),
|
||||
'first_mahadasha_elapsed_years': round(first_mahadasha_elapsed, 4),
|
||||
'first_mahadasha_lord': nak_lord,
|
||||
}
|
||||
|
||||
|
||||
def calc_sub_lord(longitude: float, division: int = 9) -> Dict:
|
||||
"""
|
||||
Sub-Lord计算(KP占星体系)
|
||||
将星宿进一步细分为Sub-Lord和Sub-Sub-Lord
|
||||
|
||||
参数:
|
||||
longitude: 恒星黄道经度
|
||||
division: 细分层级(9=Sub-Lord, 81=Sub-Sub-Lord)
|
||||
"""
|
||||
# 主星宿
|
||||
nak = find_nakshatra(longitude)
|
||||
nak_span = 360.0 / 27
|
||||
|
||||
# Sub-Lord: 将星宿按守护星的大运年数比例细分
|
||||
total_dasha_years = sum(NAK_YEARS) # 120年
|
||||
nak_lord = NAK_NAMES[nak['nakshatra_idx']]
|
||||
|
||||
# 计算Sub-Lord
|
||||
deg_in_nak = nak['degree_in_nakshatra']
|
||||
sub_lord_span = nak_span * (NAK_YEARS[NAK_LORDS.index(NAK_LORDS[nak['nakshatra_idx']])]) / total_dasha_years
|
||||
|
||||
# 简化版:直接按9等分
|
||||
sub_span = nak_span / 9
|
||||
sub_idx = int(deg_in_nak / sub_span) % 9
|
||||
|
||||
# Sub-Lord是第sub_idx个行星(从星宿守护星开始的大运顺序)
|
||||
DASHA_ORDER = ["Ketu","Venus","Sun","Moon","Mars","Rahu","Jupiter","Saturn","Mercury"]
|
||||
nak_lord_idx = DASHA_ORDER.index(NAK_LORDS[nak['nakshatra_idx']])
|
||||
sub_lord = DASHA_ORDER[(nak_lord_idx + sub_idx) % 9]
|
||||
|
||||
return {
|
||||
'nakshatra': nak['nakshatra'],
|
||||
'nakshatra_lord': nak_lord,
|
||||
'sub_lord': sub_lord,
|
||||
'sub_index': sub_idx,
|
||||
'pada': nak['pada'],
|
||||
'degree_in_nakshatra': round(deg_in_nak, 4),
|
||||
}
|
||||
|
||||
|
||||
def nakshatra_compatibility(nak1_idx: int, nak2_idx: int) -> Dict:
|
||||
"""
|
||||
Nakshatra兼容性分析(Koota系统中的星宿匹配部分)
|
||||
基于Tara Bala和Nakshatra元素匹配
|
||||
"""
|
||||
# Tara匹配
|
||||
tara = calc_tara_bala(nak1_idx, nak2_idx)
|
||||
tara_score = 3 if tara['is_auspicious'] else 0 if tara['is_dangerous'] else 1.5
|
||||
|
||||
# 元素匹配
|
||||
el1 = NAK_ELEMENT.get(nak1_idx, '')
|
||||
el2 = NAK_ELEMENT.get(nak2_idx, '')
|
||||
el_compatible = el1 == el2 or (el1 in ('火','风') and el2 in ('火','风')) or (el1 in ('土','水') and el2 in ('土','水'))
|
||||
|
||||
# Gana匹配
|
||||
g1 = NAK_GANA.get(nak1_idx, '')
|
||||
g2 = NAK_GANA.get(nak2_idx, '')
|
||||
gana_score = 6 if g1 == g2 else 3 if ('Dev' in g1 and 'Manushya' in g2) or ('Manushya' in g1 and 'Dev' in g2) else 0
|
||||
|
||||
return {
|
||||
'nak1': NAK_NAMES[nak1_idx],
|
||||
'nak2': NAK_NAMES[nak2_idx],
|
||||
'tara_bala': tara,
|
||||
'tara_score': tara_score,
|
||||
'element_match': {'e1': el1, 'e2': el2, 'compatible': el_compatible},
|
||||
'gana_match': {'g1': g1, 'g2': g2, 'score': gana_score},
|
||||
'overall': 'compatible' if tara_score >= 1.5 and el_compatible else 'challenging' if tara['is_dangerous'] else 'moderate',
|
||||
}
|
||||
|
||||
|
||||
def _tara_interp(idx):
|
||||
interps = {
|
||||
0: '生命Tara—中性,代表自我,不吉不凶',
|
||||
1: '财富Tara—吉,带来物质和精神增长',
|
||||
2: '危险Tara—凶,需要谨慎,可能带来损失',
|
||||
3: '安全Tara—吉,提供保护和稳定',
|
||||
4: '障碍Tara—凶,可能面临困难和延误',
|
||||
5: '成就Tara—吉,有利于实现目标',
|
||||
6: '毁灭Tara—凶,最大凶Tara,需特别注意',
|
||||
7: '友好Tara—吉,提供支持和帮助',
|
||||
8: '至友Tara—大吉,最强吉Tara',
|
||||
}
|
||||
return interps.get(idx, '')
|
||||
@@ -0,0 +1,434 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
synastry.py — 合盘分析模块
|
||||
Ashta Koota 36分制 + Mangal Dosha + Papasamya + Dasha兼容性
|
||||
|
||||
依赖: swisseph (可选,用于从出生数据直接计算)
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
|
||||
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
||||
|
||||
# 27 Nakshatras: (name, lord, yoni)
|
||||
NAK27 = [
|
||||
("Ashwini",0),("Bharani",1),("Krittika",2),("Rohini",3),("Mrigashira",4),
|
||||
("Ardra",5),("Punarvasu",6),("Pushya",7),("Ashlesha",8),("Magha",0),
|
||||
("Purva Phalguni",1),("Uttara Phalguni",2),("Hasta",3),("Chitra",4),
|
||||
("Swati",5),("Vishakha",6),("Anuradha",7),("Jyeshtha",8),("Mula",0),
|
||||
("Purva Ashadha",1),("Uttara Ashadha",2),("Shravana",3),("Dhanishta",4),
|
||||
("Shatabhisha",5),("Purva Bhadrapada",6),("Uttara Bhadrapada",7),("Revati",8),
|
||||
]
|
||||
# Gana: Deva(0)=0,1,6,7,14; Manushya(1)=2,4,8,10,12,15,18,20,22; Rakshasa(2)=3,5,9,11,13,16,17,19,21,23,24,25,26
|
||||
GANA_MAP = [0,0,1,2,1,2,0,0,1,2,1,2,1,2,0,1,2,2,2,2,1,2,1,2,2,2,2]
|
||||
# Yoni: 14种动物配对
|
||||
YONI_MAP = [0,1,2,3,4,5,6,7,2,0,1,8,3,4,5,6,7,8,9,1,8,3,10,4,5,6,11]
|
||||
YONI_NAME = ['Horse','Elephant','Sheep','Serpent','Dog','Cat','Rat','Cow','Buffalo',
|
||||
'Tiger','Lion','Fish','?','?']
|
||||
# Nadi: 3种 (Vata=0, Pitta=1, Kapha=2)
|
||||
NADI_MAP = [0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2]
|
||||
# Varna: 4种种姓 (Brahmin=3, Kshatriya=2, Vaishya=1, Shudra=0)
|
||||
VARNA_MAP = [0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1]
|
||||
# Vashya: sign-based
|
||||
VASHYA_SIGN = [0,1,2,3,0,1,2,3,0,1,2,3] # 0=quadruped,1=biped,2=insect,3=water
|
||||
|
||||
# Dasha years for Vimshottari
|
||||
DASHA_YEARS = {"Ketu":7,"Venus":20,"Sun":6,"Moon":10,"Mars":7,"Rahu":18,"Jupiter":16,"Saturn":19,"Mercury":17}
|
||||
DASHA_ORDER = ["Ketu","Venus","Sun","Moon","Mars","Rahu","Jupiter","Saturn","Mercury"]
|
||||
|
||||
def _nak_idx(lon):
|
||||
"""黄经→Nakshatra索引(0-26)"""
|
||||
return int(lon / (360/27)) % 27
|
||||
|
||||
def _sign_idx(lon):
|
||||
return int(lon / 30) % 12
|
||||
|
||||
# ============================================================================
|
||||
# Ashta Koota 8维度评分
|
||||
# ============================================================================
|
||||
def _calc_varna(n1, n2):
|
||||
"""Varna Koota (1分) - 精神兼容"""
|
||||
v1, v2 = VARNA_MAP[n1], VARNA_MAP[n2]
|
||||
if v2 >= v1: return {'score':1,'max':1,'v1':v1,'v2':v2,'note':'女方种姓≥男方,吉'}
|
||||
return {'score':0,'max':1,'v1':v1,'v2':v2,'note':'女方种姓<男方,不吉'}
|
||||
|
||||
def _calc_vashya(s1, s2):
|
||||
"""Vashya Koota (2分) - 控制力"""
|
||||
v1, v2 = VASHYA_SIGN[s1], VASHYA_SIGN[s2]
|
||||
if v1 == v2: return {'score':2,'max':2,'note':'同Vashya,满分'}
|
||||
# 互补对
|
||||
pairs = {(0,3),(3,0),(1,2),(2,1)}
|
||||
if (v1,v2) in pairs: return {'score':1,'max':2,'note':'互补Vashya,半分'}
|
||||
return {'score':0,'max':2,'note':'Vashya不合'}
|
||||
|
||||
def _calc_tara(n1, n2):
|
||||
"""Tara Koota (3分) - 星宿距离吉凶"""
|
||||
diff = (n2 - n1) % 9
|
||||
auspicious = {0,2,4,6,8} # Janma,Sampat,Kshema,Pratyak,Sadhana → 2,4,6,8,0 mod9
|
||||
# 好Tara: Sampat(2),Kshema(4),Sadhana(6),Priya(8)
|
||||
good = {2,4,6,8}
|
||||
if diff in good: return {'score':3,'max':3,'diff':diff,'note':'吉Tara'}
|
||||
if diff == 0: return {'score':2,'max':3,'diff':diff,'note':'中性Tara(Janma)'}
|
||||
return {'score':0,'max':3,'diff':diff,'note':'凶Tara'}
|
||||
|
||||
def _calc_yoni(n1, n2):
|
||||
"""Yoni Koota (4分) - 生理兼容"""
|
||||
y1, y2 = YONI_MAP[n1], YONI_MAP[n2]
|
||||
if y1 == y2: return {'score':4,'max':4,'note':'同Yoni,满分'}
|
||||
# 敌对Yoni
|
||||
enemy = {(0,5),(5,0),(2,4),(4,2),(3,2),(2,3)}
|
||||
if (y1,y2) in enemy: return {'score':0,'max':4,'note':'敌对Yoni'}
|
||||
# 友好Yoni
|
||||
friendly = {(0,7),(7,0),(1,8),(8,1),(6,9),(9,6)}
|
||||
if (y1,y2) in friendly: return {'score':3,'max':4,'note':'友好Yoni'}
|
||||
return {'score':1,'max':4,'note':'中性Yoni'}
|
||||
|
||||
def _calc_graha_maitri(lord1, lord2):
|
||||
"""Graha Maitri Koota (5分) - 行星友谊"""
|
||||
# 行星友谊表
|
||||
friends = {'Sun':['Moon','Mars','Jupiter'],'Moon':['Sun','Mercury'],
|
||||
'Mars':['Sun','Moon','Jupiter'],'Mercury':['Sun','Venus'],
|
||||
'Jupiter':['Sun','Moon','Mars'],'Venus':['Mercury','Saturn'],
|
||||
'Saturn':['Mercury','Venus'],'Rahu':['Venus','Saturn'],
|
||||
'Ketu':['Venus','Saturn']}
|
||||
enemies = {'Sun':['Saturn','Venus'],'Moon':['Mercury'],'Mars':['Mercury','Saturn'],
|
||||
'Mercury':['Mars','Jupiter','Saturn'],'Jupiter':['Mercury','Venus'],
|
||||
'Venus':['Sun','Moon','Mars'],'Saturn':['Sun','Moon','Mars'],
|
||||
'Rahu':['Sun','Moon','Mars'],'Ketu':['Sun','Moon','Mars']}
|
||||
if lord1 == lord2: return {'score':5,'max':5,'note':'同主星,满分'}
|
||||
l2_friends = friends.get(lord2,[])
|
||||
l2_enemies = enemies.get(lord2,[])
|
||||
if lord1 in l2_friends: return {'score':4,'max':5,'note':f'{lord1}是{lord2}的友星'}
|
||||
if lord1 in l2_enemies: return {'score':0,'max':5,'note':f'{lord1}是{lord2}的敌星'}
|
||||
return {'score':2,'max':5,'note':f'{lord1}对{lord2}中性'}
|
||||
|
||||
def _calc_gana(n1, n2):
|
||||
"""Gana Koota (6分) - 气质类型"""
|
||||
g1, g2 = GANA_MAP[n1], GANA_MAP[n2]
|
||||
gana_name = {0:'Deva(天神)',1:'Manushya(人类)',2:'Rakshasa(罗刹)'}
|
||||
if g1 == g2: return {'score':6,'max':6,'g1':gana_name[g1],'g2':gana_name[g2],'note':'同Gana,满分'}
|
||||
# Deva+Manushya
|
||||
combo = {g1,g2}
|
||||
if combo == {0,1}: return {'score':5,'max':6,'g1':gana_name[g1],'g2':gana_name[g2],'note':'天神+人类,良好'}
|
||||
if combo == {1,2}: return {'score':2,'max':6,'g1':gana_name[g1],'g2':gana_name[g2],'note':'人类+罗刹,较差'}
|
||||
# Deva+Rakshasa
|
||||
return {'score':1,'max':6,'g1':gana_name[g1],'g2':gana_name[g2],'note':'天神+罗刹,很差'}
|
||||
|
||||
def _calc_bhakuta(n1, n2):
|
||||
"""Bhakuta Koota (7分) - 情感+经济"""
|
||||
diff = (n2 - n1) % 9
|
||||
# 满分组合
|
||||
full = {1,3,5,7}
|
||||
if diff in full: return {'score':7,'max':7,'diff':diff,'note':'吉Bhakuta,满分'}
|
||||
if diff == 0: return {'score':4,'max':7,'diff':diff,'note':'中性Bhakuta'}
|
||||
return {'score':0,'max':7,'diff':diff,'note':'凶Bhakuta,零分'}
|
||||
|
||||
def _calc_nadi(n1, n2):
|
||||
"""Nadi Koota (8分) - 生命力/健康"""
|
||||
na1, na2 = NADI_MAP[n1], NADI_MAP[n2]
|
||||
nadi_name = {0:'Vata(风)',1:'Pitta(胆汁)',2:'Kapha(粘液)'}
|
||||
if na1 == na2:
|
||||
return {'score':0,'max':8,'n1':nadi_name[na1],'n2':nadi_name[na2],
|
||||
'note':'同Nadi=不吉(传统认为影响后代健康)'}
|
||||
return {'score':8,'max':8,'n1':nadi_name[na1],'n2':nadi_name[na2],
|
||||
'note':'不同Nadi=吉,互补生命力'}
|
||||
|
||||
# ============================================================================
|
||||
# 合盘主函数
|
||||
# ============================================================================
|
||||
def calc_synastry(person1: dict, person2: dict) -> dict:
|
||||
"""
|
||||
计算两人的完整合盘分析
|
||||
|
||||
person1/person2 格式:
|
||||
{
|
||||
'moon_lon': float, # 月亮黄经(恒星黄道)
|
||||
'mars_lon': float, # 火星黄经(恒星黄道) (可选)
|
||||
'asc_lon': float, # 上升黄经(恒星黄道) (可选)
|
||||
'nakshatra_lord': str, # 月亮Nakshatra主星 (可选,自动计算)
|
||||
'gender': str, # 'M' or 'F' (影响Varna方向)
|
||||
}
|
||||
|
||||
返回: 完整合盘报告 dict
|
||||
"""
|
||||
m1 = person1.get('moon_lon', 0)
|
||||
m2 = person2.get('moon_lon', 0)
|
||||
n1 = _nak_idx(m1)
|
||||
n2 = _nak_idx(m2)
|
||||
s1 = _sign_idx(m1)
|
||||
s2 = _sign_idx(m2)
|
||||
|
||||
# Nakshatra主星
|
||||
lords = ['Ketu','Venus','Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury']
|
||||
lord1 = person1.get('nakshatra_lord') or lords[n1 % 9]
|
||||
lord2 = person2.get('nakshatra_lord') or lords[n2 % 9]
|
||||
|
||||
# Ashta Koota 8维度
|
||||
varna = _calc_varna(n1, n2)
|
||||
vashya = _calc_vashya(s1, s2)
|
||||
tara = _calc_tara(n1, n2)
|
||||
yoni = _calc_yoni(n1, n2)
|
||||
graha = _calc_graha_maitri(lord1, lord2)
|
||||
gana = _calc_gana(n1, n2)
|
||||
bhakuta = _calc_bhakuta(n1, n2)
|
||||
nadi = _calc_nadi(n1, n2)
|
||||
|
||||
kootas = [
|
||||
('Varna(精神)', varna), ('Vashya(控制)', vashya), ('Tara(星宿距离)', tara),
|
||||
('Yoni(生理)', yoni), ('Graha Maitri(行星友谊)', graha),
|
||||
('Gana(气质)', gana), ('Bhakuta(情感经济)', bhakuta), ('Nadi(生命力)', nadi),
|
||||
]
|
||||
|
||||
total = sum(k[1]['score'] for k in kootas)
|
||||
max_total = sum(k[1]['max'] for k in kootas)
|
||||
pct = round(total / max_total * 100, 1) if max_total else 0
|
||||
|
||||
# 综合判定
|
||||
verdict = _compatibility_verdict(total, pct)
|
||||
|
||||
# Mangal Dosha 检查
|
||||
dosha1 = _check_mangal_dosha(person1)
|
||||
dosha2 = _check_mangal_dosha(person2)
|
||||
mangal_note = _dosha_match(dosha1, dosha2)
|
||||
|
||||
# Papasamya (双方凶星抵消度)
|
||||
papasamya = _calc_papasamya(person1, person2)
|
||||
|
||||
return {
|
||||
'method': 'Ashta Koota 36分制 + Mangal Dosha + Papasamya',
|
||||
'version': '3.7',
|
||||
'person1': {'moon_nakshatra': NAK27[n1][0], 'nak_idx': n1, 'moon_sign': SIGNS[s1]},
|
||||
'person2': {'moon_nakshatra': NAK27[n2][0], 'nak_idx': n2, 'moon_sign': SIGNS[s2]},
|
||||
'kootas': {k:v for k,v in kootas},
|
||||
'total_score': total,
|
||||
'max_score': max_total,
|
||||
'percentage': pct,
|
||||
'verdict': verdict,
|
||||
'mangal_dosha': {'person1': dosha1, 'person2': dosha2, 'compatibility': mangal_note},
|
||||
'papasamya': papasamya,
|
||||
'recommendations': _generate_recommendations(total, pct, kootas, mangal_note),
|
||||
}
|
||||
|
||||
|
||||
def _compatibility_verdict(score, pct):
|
||||
"""综合判定"""
|
||||
if pct >= 75: return {'level':'极佳','color':'绿色','cn':'强烈推荐,天然契合'}
|
||||
if pct >= 60: return {'level':'良好','color':'蓝绿','cn':'推荐,小问题可化解'}
|
||||
if pct >= 45: return {'level':'一般','color':'黄色','cn':'需要努力调和'}
|
||||
if pct >= 30: return {'level':'较差','color':'橙色','cn':'不推荐,阻力较大'}
|
||||
return {'level':'很差','color':'红色','cn':'强烈不推荐,冲突严重'}
|
||||
|
||||
|
||||
def _check_mangal_dosha(person):
|
||||
"""Mangal Dosha(火星凶相)检查"""
|
||||
mars_lon = person.get('mars_lon')
|
||||
if mars_lon is None:
|
||||
return {'has_dosha': None, 'note': '缺少火星数据'}
|
||||
mars_house = person.get('mars_house')
|
||||
mars_sign = _sign_idx(mars_lon) if mars_house is None else None
|
||||
|
||||
# 需要计算火星在第几宫(相对于上升)
|
||||
asc_lon = person.get('asc_lon')
|
||||
if asc_lon is not None and mars_house is None:
|
||||
asc_si = _sign_idx(asc_lon)
|
||||
mars_si = _sign_idx(mars_lon)
|
||||
mars_house = ((mars_si - asc_si) % 12) + 1
|
||||
|
||||
if mars_house is None:
|
||||
return {'has_dosha': None, 'note': '缺少上升数据,无法确定宫位'}
|
||||
|
||||
# Mangal Dosha: 火星在1/2/4/7/8/12宫
|
||||
dosha_houses = {1, 2, 4, 7, 8, 12}
|
||||
has = mars_house in dosha_houses
|
||||
|
||||
# 强度分级
|
||||
severity = '无'
|
||||
if has:
|
||||
if mars_house in {7, 8}:
|
||||
severity = '强'
|
||||
elif mars_house in {1, 2}:
|
||||
severity = '中'
|
||||
else:
|
||||
severity = '轻'
|
||||
|
||||
return {
|
||||
'has_dosha': has,
|
||||
'severity': severity if has else '无',
|
||||
'mars_house': mars_house,
|
||||
'note': f'火星在第{mars_house}宫' + ('→有Mangal Dosha' if has else '→无Mangal Dosha'),
|
||||
}
|
||||
|
||||
|
||||
def _dosha_match(dosha1, dosha2):
|
||||
"""双方Mangal Dosha匹配"""
|
||||
d1 = dosha1.get('has_dosha')
|
||||
d2 = dosha2.get('has_dosha')
|
||||
if d1 is None or d2 is None:
|
||||
return {'status':'数据不足','note':'缺少一方火星数据'}
|
||||
if d1 and d2:
|
||||
return {'status':'双Dosha匹配','note':'双方都有Mangal Dosha,互相抵消→可接受'}
|
||||
if d1 and not d2:
|
||||
return {'status':'仅一方Dosha','note':'仅Person1有Dosha,Person2需有足够力量承受'}
|
||||
if not d1 and d2:
|
||||
return {'status':'仅一方Dosha','note':'仅Person2有Dosha,Person1需有足够力量承受'}
|
||||
return {'status':'双方无Dosha','note':'双方均无Mangal Dosha→理想'}
|
||||
|
||||
|
||||
def _calc_papasamya(p1, p2):
|
||||
"""Papasamya - 双方凶星点数抵消"""
|
||||
# 简化版:检查太阳/火星/土星/北交点在凶宫(6/8/12)的情况
|
||||
def _count_papa(person):
|
||||
count = 0
|
||||
for key in ['sun_house','mars_house','saturn_house','rahu_house']:
|
||||
h = person.get(key)
|
||||
if h and h in {6, 8, 12}:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
c1 = _count_papa(p1)
|
||||
c2 = _count_papa(p2)
|
||||
diff = abs(c1 - c2)
|
||||
|
||||
if diff == 0:
|
||||
balance = '均衡'
|
||||
note = '双方凶星负担相当,Papasamya良好'
|
||||
elif diff == 1:
|
||||
balance = '轻微失衡'
|
||||
note = '一方凶星负担略重,可接受'
|
||||
else:
|
||||
balance = '明显失衡'
|
||||
note = '双方凶星负担差异较大,需注意'
|
||||
|
||||
return {'person1_papa': c1, 'person2_papa': c2, 'difference': diff,
|
||||
'balance': balance, 'note': note}
|
||||
|
||||
|
||||
def _generate_recommendations(score, pct, kootas, mangal_note):
|
||||
"""生成建议"""
|
||||
recs = []
|
||||
|
||||
# 低分维度警告
|
||||
for name, data in kootas:
|
||||
if data['score'] < data['max'] * 0.3:
|
||||
recs.append(f"⚠ {name}得分低({data['score']}/{data['max']}):{data['note']}")
|
||||
|
||||
# Nadi特别警告
|
||||
nadi_score = kootas[7][1]['score'] # Nadi是第8个
|
||||
if nadi_score == 0:
|
||||
recs.append("🔴 Nadi Koota零分!传统认为同Nadi婚姻可能影响后代健康,建议咨询专业占星师")
|
||||
recs.append("化解方案:Nadi Dosha Pooja、佩戴对应宝石、或寻找Nadi不同的伴侣")
|
||||
|
||||
# Mangal Dosha建议
|
||||
if mangal_note.get('status') == '仅一方Dosha':
|
||||
recs.append("⚠ 一方有Mangal Dosha:建议找有Dosha的伴侣匹配,或进行Mangal Dosha化解仪式")
|
||||
recs.append("化解方案:Kumbh Vivah(与陶罐结婚仪式)、在28岁后结婚、或匹配有Dosha的对象")
|
||||
|
||||
# 总分建议
|
||||
if pct >= 60:
|
||||
recs.append(f"✅ 总分{pct}%,在可接受范围内。建议深入了解彼此价值观和生活目标")
|
||||
elif pct >= 45:
|
||||
recs.append(f"⚠ 总分{pct}%,需要双方更多努力和理解。建议进行详细的合盘咨询")
|
||||
else:
|
||||
recs.append(f"❌ 总分{pct}%,传统认为阻力较大。强烈建议咨询专业占星师后再做决定")
|
||||
|
||||
return recs
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Dasha 兼容性分析
|
||||
# ============================================================================
|
||||
def calc_dasha_compatibility(dasha1: list, dasha2: list, start_year: int) -> dict:
|
||||
"""
|
||||
分析两人Dasha时间线的兼容性
|
||||
|
||||
dasha1/dasha2: [{'lord':'Venus','start':'1990-01-01','end':'2010-01-01','years':20}, ...]
|
||||
start_year: 分析起始年份
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
periods = []
|
||||
conflicts = []
|
||||
harmonies = []
|
||||
|
||||
# 行星兼容性
|
||||
friends = {'Sun':['Moon','Mars','Jupiter'],'Moon':['Sun','Mercury'],
|
||||
'Mars':['Sun','Moon','Jupiter'],'Mercury':['Sun','Venus'],
|
||||
'Jupiter':['Sun','Moon','Mars'],'Venus':['Mercury','Saturn'],
|
||||
'Saturn':['Mercury','Venus'],'Rahu':['Venus','Saturn'],'Ketu':['Venus','Saturn']}
|
||||
|
||||
for d1 in dasha1:
|
||||
for d2 in dasha2:
|
||||
# 检查时间重叠
|
||||
try:
|
||||
s1 = datetime.strptime(d1['start'],'%Y-%m-%d')
|
||||
e1 = datetime.strptime(d1['end'],'%Y-%m-%d')
|
||||
s2 = datetime.strptime(d2['start'],'%Y-%m-%d')
|
||||
e2 = datetime.strptime(d2['end'],'%Y-%m-%d')
|
||||
except:
|
||||
continue
|
||||
|
||||
overlap_start = max(s1, s2)
|
||||
overlap_end = min(e1, e2)
|
||||
if overlap_start >= overlap_end:
|
||||
continue
|
||||
if overlap_start.year < start_year:
|
||||
continue
|
||||
|
||||
lord1 = d1.get('lord','')
|
||||
lord2 = d2.get('lord','')
|
||||
|
||||
# 判断关系
|
||||
l2_friends = friends.get(lord2, [])
|
||||
rel = '中性'
|
||||
if lord1 == lord2:
|
||||
rel = '同步'
|
||||
elif lord1 in l2_friends:
|
||||
rel = '友好'
|
||||
elif lord1 in ['Rahu','Ketu'] or lord2 in ['Rahu','Ketu']:
|
||||
rel = '变化'
|
||||
else:
|
||||
rel = '紧张'
|
||||
|
||||
period_info = {
|
||||
'period': f"{overlap_start.strftime('%Y-%m')} ~ {overlap_end.strftime('%Y-%m')}",
|
||||
'person1_dasha': lord1,
|
||||
'person2_dasha': lord2,
|
||||
'relationship': rel,
|
||||
}
|
||||
periods.append(period_info)
|
||||
|
||||
if rel in ('紧张','变化'):
|
||||
conflicts.append(period_info)
|
||||
elif rel in ('同步','友好'):
|
||||
harmonies.append(period_info)
|
||||
|
||||
return {
|
||||
'method': 'Dasha时间线兼容性',
|
||||
'periods_analyzed': len(periods),
|
||||
'conflicts': conflicts[:5],
|
||||
'harmonies': harmonies[:5],
|
||||
'conflict_count': len(conflicts),
|
||||
'harmony_count': len(harmonies),
|
||||
'assessment': '和谐' if len(harmonies) > len(conflicts) * 1.5 else
|
||||
('一般' if len(harmonies) >= len(conflicts) else '紧张'),
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# CLI 入口
|
||||
# ============================================================================
|
||||
if __name__ == '__main__':
|
||||
import json
|
||||
import sys
|
||||
|
||||
# 示例用法
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'test':
|
||||
p1 = {'moon_lon': 45.5, 'mars_lon': 120.3, 'asc_lon': 150.0, 'gender': 'M'}
|
||||
p2 = {'moon_lon': 200.7, 'mars_lon': 30.1, 'asc_lon': 60.0, 'gender': 'F'}
|
||||
result = calc_synastry(p1, p2)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
print("Usage: python synastry.py test")
|
||||
print(" test - 运行示例测试")
|
||||
@@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Tajika/Varshaphala年运盘模块 v1.0
|
||||
太阳返照盘分析系统
|
||||
|
||||
支持:
|
||||
- Muntha(年度上升点移动)
|
||||
- Varshaphala计算(太阳回到出生位置时的星盘)
|
||||
- Mudda Dasha(年度大运)
|
||||
- Tajika Yoga(年度特殊格局)
|
||||
- Tri-Pataka(三旗系统)
|
||||
-年度Lord(Year Lord)
|
||||
"""
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
import math
|
||||
|
||||
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
|
||||
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
||||
SIGN_LORDS = {'Aries':'Mars','Taurus':'Venus','Gemini':'Mercury','Cancer':'Moon',
|
||||
'Leo':'Sun','Virgo':'Mercury','Libra':'Venus','Scorpio':'Mars',
|
||||
'Sagittarius':'Jupiter','Capricorn':'Saturn','Aquarius':'Saturn','Pisces':'Jupiter'}
|
||||
|
||||
|
||||
def calc_muntha(birth_asc_idx: int, age: int) -> Dict:
|
||||
"""
|
||||
Muntha计算:年度上升点
|
||||
从出生上升星座开始,每年前进一个星座
|
||||
|
||||
参数:
|
||||
birth_asc_idx: 出生上升星座索引(0=Aries)
|
||||
age: 当前年龄(整数)
|
||||
"""
|
||||
muntha_idx = (birth_asc_idx + age) % 12
|
||||
muntha_sign = SIGNS[muntha_idx]
|
||||
lord = SIGN_LORDS[muntha_sign]
|
||||
|
||||
# Muntha落在的宫位(从本命盘上升算起)
|
||||
# 需要本命盘上升来计算
|
||||
|
||||
return {
|
||||
'muntha_sign': muntha_sign,
|
||||
'muntha_sign_idx': muntha_idx,
|
||||
'muntha_lord': lord,
|
||||
'age': age,
|
||||
'interpretation': _muntha_interp(muntha_sign, lord),
|
||||
}
|
||||
|
||||
|
||||
def calc_year_lord(birth_asc_idx: int, age: int) -> Dict:
|
||||
"""
|
||||
Year Lord(年度守护星)
|
||||
基于Muntha位置确定该年的守护行星
|
||||
|
||||
规则:
|
||||
- Muntha落在某星座→该星座守护星为Year Lord
|
||||
- Muntha的2/5/9/11宫的守护星为辅助
|
||||
"""
|
||||
muntha_idx = (birth_asc_idx + age) % 12
|
||||
muntha_sign = SIGNS[muntha_idx]
|
||||
year_lord = SIGN_LORDS[muntha_sign]
|
||||
|
||||
# 辅助星(2/5/9/11宫主)
|
||||
aux_houses = [2, 5, 9, 11]
|
||||
aux_lords = []
|
||||
for h in aux_houses:
|
||||
h_sign_idx = (muntha_idx + h - 1) % 12
|
||||
h_sign = SIGNS[h_sign_idx]
|
||||
aux_lords.append({'house': h, 'sign': h_sign, 'lord': SIGN_LORDS[h_sign]})
|
||||
|
||||
return {
|
||||
'age': age,
|
||||
'year_lord': year_lord,
|
||||
'muntha_sign': muntha_sign,
|
||||
'auxiliary_lords': aux_lords,
|
||||
'year_theme': _year_theme(year_lord),
|
||||
}
|
||||
|
||||
|
||||
def calc_varshaphala(birth_datetime: datetime,
|
||||
target_year: int,
|
||||
birth_lon: float, birth_lat: float,
|
||||
birth_tz: float) -> Dict:
|
||||
"""
|
||||
Varshaphala(太阳返照盘)计算
|
||||
|
||||
原理: 太阳回到出生时精确位置的时刻,重新起盘
|
||||
这个新的上升星座和行星配置代表该年的运势
|
||||
|
||||
参数:
|
||||
birth_datetime: 出生时间
|
||||
target_year: 目标年份
|
||||
birth_lon/lat: 出生经纬度
|
||||
birth_tz: 出生时区
|
||||
"""
|
||||
# 简化版:用Muntha + Year Lord + 基本Tajika规则
|
||||
# 完整版需要Swiss Ephemeris计算太阳精确返照时间
|
||||
|
||||
# 出生上升(需要传入,这里用简化版)
|
||||
age = target_year - birth_datetime.year
|
||||
|
||||
return {
|
||||
'target_year': target_year,
|
||||
'age': age,
|
||||
'note': 'Varshaphala完整计算需要Swiss Ephemeris精确返照时间',
|
||||
'components': {
|
||||
'muntha': calc_muntha(0, age), # 需要实际出生上升
|
||||
'year_lord': calc_year_lord(0, age),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def calc_mudda_dasha(asc_sign_idx: int,
|
||||
varsha_lord: str,
|
||||
birth_month: int) -> Dict:
|
||||
"""
|
||||
Mudda Dasha(年度大运)
|
||||
基于Varshaphala上升的12个月大运系统
|
||||
|
||||
规则: 从年度守护星开始,按Vimshottari顺序排列
|
||||
每个大运按比例分配12个月
|
||||
"""
|
||||
DASHA_ORDER = ["Ketu","Venus","Sun","Moon","Mars","Rahu","Jupiter","Saturn","Mercury"]
|
||||
DASHA_YEARS = {"Ketu":7,"Venus":20,"Sun":6,"Moon":10,"Mars":7,"Rahu":18,"Jupiter":16,"Saturn":19,"Mercury":17}
|
||||
|
||||
start_idx = DASHA_ORDER.index(varsha_lord) if varsha_lord in DASHA_ORDER else 0
|
||||
|
||||
sequence = []
|
||||
remaining_months = 12.0
|
||||
|
||||
for i in range(9):
|
||||
lord = DASHA_ORDER[(start_idx + i) % 9]
|
||||
years = DASHA_YEARS[lord]
|
||||
months = years * 12.0 / 120.0 # 按比例分配
|
||||
|
||||
if months > remaining_months:
|
||||
months = remaining_months
|
||||
remaining_months -= months
|
||||
|
||||
sequence.append({
|
||||
'lord': lord,
|
||||
'months': round(months, 2),
|
||||
'order': i + 1,
|
||||
})
|
||||
|
||||
if remaining_months <= 0:
|
||||
break
|
||||
|
||||
return {
|
||||
'varsha_lord': varsha_lord,
|
||||
'dasha_sequence': sequence,
|
||||
'total_months': 12,
|
||||
}
|
||||
|
||||
|
||||
def calc_tri_pataka(planet_lons: Dict[str, float],
|
||||
varsha_lord: str,
|
||||
muntha_sign_idx: int) -> Dict:
|
||||
"""
|
||||
Tri-Pataka(三旗系统)
|
||||
Tajika占星中判断年度吉凶的重要技法
|
||||
|
||||
三旗:
|
||||
1. Dasha Lord(大运守护星)的强度
|
||||
2. Muntha Lord(Muntha守护星)的强度
|
||||
3. Year Lord(年度守护星)的强度
|
||||
|
||||
三者都强→大吉年;三者都弱→凶年
|
||||
"""
|
||||
muntha_lord = SIGN_LORDS.get(SIGNS[muntha_sign_idx], '')
|
||||
|
||||
# 评估各守护星强度(简化版)
|
||||
def _strength(planet, lons):
|
||||
if planet not in lons:
|
||||
return 'unknown'
|
||||
lon = lons[planet]
|
||||
si = int(lon / 30) % 12
|
||||
# 简化:在角宫(1/4/7/10)=强,三方(5/9)=中,其他=弱
|
||||
house_from_asc = ((si - muntha_sign_idx) % 12) + 1
|
||||
if house_from_asc in (1, 4, 7, 10): return 'strong'
|
||||
if house_from_asc in (5, 9): return 'moderate'
|
||||
return 'weak'
|
||||
|
||||
dl_strength = _strength(varsha_lord, planet_lons)
|
||||
ml_strength = _strength(muntha_lord, planet_lons)
|
||||
yl_strength = _strength(varsha_lord, planet_lons)
|
||||
|
||||
strong_count = sum(1 for s in [dl_strength, ml_strength, yl_strength] if s == 'strong')
|
||||
weak_count = sum(1 for s in [dl_strength, ml_strength, yl_strength] if s == 'weak')
|
||||
|
||||
if strong_count >= 2: verdict = 'excellent'
|
||||
elif weak_count >= 2: verdict = 'challenging'
|
||||
else: verdict = 'mixed'
|
||||
|
||||
return {
|
||||
'dasha_lord': {'planet': varsha_lord, 'strength': dl_strength},
|
||||
'muntha_lord': {'planet': muntha_lord, 'strength': ml_strength},
|
||||
'year_lord': {'planet': varsha_lord, 'strength': yl_strength},
|
||||
'verdict': verdict,
|
||||
'interpretation': {
|
||||
'excellent': '三旗中两旗以上强旺,年度运势极佳',
|
||||
'mixed': '三旗力量参差不齐,年度运势起伏',
|
||||
'challenging': '三旗中两旗以上衰弱,年度运势挑战较大',
|
||||
}.get(verdict, ''),
|
||||
}
|
||||
|
||||
|
||||
def _muntha_interp(sign, lord):
|
||||
"""Muntha在12星座的基本解读"""
|
||||
interps = {
|
||||
'Aries': '年度主题:新开始、冒险、独立行动',
|
||||
'Taurus': '年度主题:财务稳定、物质积累、感官享受',
|
||||
'Gemini': '年度主题:学习、沟通、多元发展',
|
||||
'Cancer': '年度主题:家庭、情感、内在安全感',
|
||||
'Leo': '年度主题:创造力、领导力、自我表达',
|
||||
'Virgo': '年度主题:健康、服务、细节完善',
|
||||
'Libra': '年度主题:关系、合作、美学追求',
|
||||
'Scorpio': '年度主题:转化、深层变革、隐藏事物',
|
||||
'Sagittarius': '年度主题:远方旅行、哲学、高等教育',
|
||||
'Capricorn': '年度主题:事业成就、社会地位、长期规划',
|
||||
'Aquarius': '年度主题:社交网络、创新、人道主义',
|
||||
'Pisces': '年度主题:灵性成长、隐退、创意灵感',
|
||||
}
|
||||
return interps.get(sign, '')
|
||||
|
||||
|
||||
def _year_theme(lord):
|
||||
"""年度守护星主题"""
|
||||
themes = {
|
||||
'Sun': '权威、政府、父亲、领导力',
|
||||
'Moon': '公众、母亲、情感、直觉',
|
||||
'Mars': '行动、竞争、房地产、手术',
|
||||
'Mercury': '沟通、商业、学习、旅行',
|
||||
'Jupiter': '智慧、子女、宗教、财富',
|
||||
'Venus': '爱情、艺术、奢侈品、婚姻',
|
||||
'Saturn': '纪律、长寿、建筑、责任',
|
||||
}
|
||||
return themes.get(lord, '')
|
||||
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
吠陀占星分盘计算模块 v1.0
|
||||
BPHS Shodasavarga(十六分盘体系)
|
||||
支持: D2/D3/D4/D7/D9/D10/D12/D16/D20/D24/D27/D30/D40/D45/D60
|
||||
每个分盘输出精确度数,支持进一步分析。
|
||||
"""
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
|
||||
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
||||
SIGNS_CN = {s: f"{cn}" for s, cn in zip(SIGNS,
|
||||
['白羊座','金牛座','双子座','巨蟹座','狮子座','处女座',
|
||||
'天秤座','天蝎座','射手座','摩羯座','水瓶座','双鱼座'])}
|
||||
SIGN_LORDS = {'Aries':'Mars','Taurus':'Venus','Gemini':'Mercury','Cancer':'Moon',
|
||||
'Leo':'Sun','Virgo':'Mercury','Libra':'Venus','Scorpio':'Mars',
|
||||
'Sagittarius':'Jupiter','Capricorn':'Saturn','Aquarius':'Saturn','Pisces':'Jupiter'}
|
||||
EXALT_SIGN = {'Sun':0,'Moon':1,'Mars':9,'Mercury':5,'Jupiter':3,'Venus':11,'Saturn':6}
|
||||
DEBIL_SIGN = {'Sun':6,'Moon':7,'Mars':3,'Mercury':11,'Jupiter':9,'Venus':5,'Saturn':0}
|
||||
OWN_SIGNS = {'Sun':[4],'Moon':[3],'Mars':[0,7],'Mercury':[2,5],
|
||||
'Jupiter':[8,11],'Venus':[1,6],'Saturn':[9,10]}
|
||||
VARGA_META = {
|
||||
2:{'name':'Hora','cn':'财富','area':'财富资源'},3:{'name':'Drekkana','cn':'兄弟','area':'兄弟姐妹'},
|
||||
4:{'name':'Turyamsa','cn':'财产','area':'财产住所'},7:{'name':'Saptamsa','cn':'子女','area':'子女后代'},
|
||||
9:{'name':'Navamsa','cn':'婚姻','area':'婚姻伴侣灵魂'},10:{'name':'Dasamsa','cn':'事业','area':'事业公众形象'},
|
||||
12:{'name':'Dwadashamsa','cn':'父母','area':'父母祖先'},16:{'name':'Shodasamsa','cn':'享受','area':'车辆物质'},
|
||||
20:{'name':'Vimsamsa','cn':'修行','area':'精神修行'},24:{'name':'Siddhamsa','cn':'学识','area':'教育学识'},
|
||||
27:{'name':'Bhamsa','cn':'力量','area':'力量弱点'},30:{'name':'Trimsamsa','cn':'苦难','area':'灾难苦难'},
|
||||
40:{'name':'Khavedamsa','cn':'运势','area':'吉凶运势'},45:{'name':'Akshavedamsa','cn':'格局','area':'整体格局'},
|
||||
60:{'name':'Shashtyamsa','cn':'业力','area':'前世业力同盘区分'}}
|
||||
|
||||
def _si(lon): return int(lon/30)%12
|
||||
def _sn(i): return SIGNS[i%12]
|
||||
def _odd(si): return si%2==0 # Aries(0)=odd
|
||||
|
||||
def _d30_map(si, pi):
|
||||
if _odd(si):
|
||||
if pi<5: return 0
|
||||
if pi<10: return 10
|
||||
if pi<18: return 8
|
||||
if pi<25: return 2
|
||||
return 6
|
||||
else:
|
||||
if pi<5: return 1
|
||||
if pi<12: return 5
|
||||
if pi<20: return 9
|
||||
if pi<25: return 7
|
||||
return 11
|
||||
|
||||
def varga_map(si, pi, div):
|
||||
"""BPHS分盘映射:星座索引si的第pi份→目标星座索引"""
|
||||
o = _odd(si)
|
||||
if div==2: return (4 if o else 3) if pi==0 else (3 if o else 4)
|
||||
if div==3: return (si+pi*4)%12 if o else (si+8+pi*4)%12
|
||||
if div==4: return (si+pi)%12 if o else (si+8+pi)%12
|
||||
if div==7: return (si+pi)%12 if o else (si+6+pi)%12
|
||||
if div==9:
|
||||
el={0:0,1:9,2:6,3:3}; return (el[si%4]+pi)%12
|
||||
if div==10: return (si+pi)%12 if o else (si+8+pi)%12
|
||||
if div==12: return (si+pi)%12
|
||||
if div==16: return ((0 if o else 1)+pi)%12
|
||||
if div==20: return ((0 if o else 8)+pi)%12
|
||||
if div==24: return ((4 if o else 3)+pi)%12
|
||||
if div==27: return ((0 if o else 6)+pi)%12
|
||||
if div==30: return _d30_map(si,pi)
|
||||
if div==40: return ((0 if o else 6)+pi)%12
|
||||
if div==45: return ((0 if o else 6)+pi)%12
|
||||
if div==60: return (si+pi)%12 if o else (si+1+pi)%12
|
||||
raise ValueError(f"不支持的D{div}")
|
||||
|
||||
def calc_varga(lon, div):
|
||||
"""计算行星在指定分盘的位置(星座+精确度数+尊贵状态)"""
|
||||
si=_si(lon); d=lon-si*30; ps=30.0/div; pi=int(d/ps); dp=d-pi*ps
|
||||
vsi=varga_map(si,pi,div)
|
||||
r={'sign':_sn(vsi),'sign_idx':vsi,'degree_in_sign':round(dp,4),
|
||||
'part_index':pi,'lord':SIGN_LORDS.get(_sn(vsi),'')}
|
||||
if div==9: r['pada']=pi+1
|
||||
return r
|
||||
|
||||
def dignity(planet, sign_idx):
|
||||
if planet in EXALT_SIGN and sign_idx==EXALT_SIGN[planet]: return 'Exalted'
|
||||
if planet in DEBIL_SIGN and sign_idx==DEBIL_SIGN[planet]: return 'Debilitated'
|
||||
if planet in OWN_SIGNS and sign_idx in OWN_SIGNS[planet]: return 'Own Sign'
|
||||
return 'Neutral'
|
||||
|
||||
def calc_all_vargas(planet_lons, asc_lon, divisions=None):
|
||||
"""批量计算所有指定分盘"""
|
||||
if divisions is None:
|
||||
divisions=[2,3,4,7,9,10,12,16,20,24,27,30,40,45,60]
|
||||
results={}
|
||||
for div in divisions:
|
||||
m=VARGA_META.get(div,{})
|
||||
key=f"D{div}_{m.get('name',f'D{div}')}"
|
||||
vd={'_meta':{'div':div,'name':m.get('name',''),'cn':m.get('cn',''),
|
||||
'area':m.get('area',''),'part_size':30.0/div}}
|
||||
vd['Ascendant']=calc_varga(asc_lon,div)
|
||||
for pn,lon in planet_lons.items():
|
||||
vd[pn]=calc_varga(lon,div)
|
||||
# 尊贵状态
|
||||
vd['_dignity']={pn:dignity(pn,pd['sign_idx'])
|
||||
for pn,pd in vd.items() if pn not in ('Ascendant','_meta') and isinstance(pd,dict) and 'sign_idx' in pd}
|
||||
# D9专项
|
||||
if div==9:
|
||||
ai=vd['Ascendant']['sign_idx']
|
||||
s7=(ai+6)%12
|
||||
p7=[pn for pn,pd in vd.items() if isinstance(pd,dict) and pd.get('sign_idx')==s7]
|
||||
vd['_d9_analysis']={
|
||||
'navamsa_7th_sign':_sn(s7),'navamsa_7th_lord':SIGN_LORDS.get(_sn(s7),''),
|
||||
'planets_in_d9_7th':p7,
|
||||
'venus_d9':f"{vd.get('Venus',{}).get('sign','?')} {vd.get('Venus',{}).get('degree_in_sign',0):.2f}°",
|
||||
'jupiter_d9':f"{vd.get('Jupiter',{}).get('sign','?')} {vd.get('Jupiter',{}).get('degree_in_sign',0):.2f}°",
|
||||
'venus_dignity':dignity('Venus',vd.get('Venus',{}).get('sign_idx',-1)),
|
||||
'jupiter_dignity':dignity('Jupiter',vd.get('Jupiter',{}).get('sign_idx',-1)),
|
||||
}
|
||||
# D60专项
|
||||
if div==60:
|
||||
ai=vd['Ascendant']['sign_idx']
|
||||
ben,mal=[],[]
|
||||
for pn,pd in vd.items():
|
||||
if not isinstance(pd,dict) or 'sign_idx' not in pd: continue
|
||||
h=((pd['sign_idx']-ai)%12)+1
|
||||
if h in (1,4,7,10):
|
||||
if pn in ('Jupiter','Venus','Moon'): ben.append(f"{pn}({h}宫)")
|
||||
elif pn in ('Saturn','Mars','Sun','Rahu','Ketu'): mal.append(f"{pn}({h}宫)")
|
||||
vd['_d60_analysis']={'benefics_in_kendras':ben,'malefics_in_kendras':mal,
|
||||
'karma_hint':'前世善业较重' if len(ben)>len(mal) else '前世有业力课题' if len(mal)>len(ben) else '善恶交织'}
|
||||
results[key]=vd
|
||||
return results
|
||||
Reference in New Issue
Block a user