fix(varga): source D5/D6/D8/D11 from PVR 6.2 (BUG-1260, upstream f32472b5)
This commit is contained in:
@@ -16917,3 +16917,19 @@
|
||||
- 防复发:上述测试;以后凡是对会话发 PATCH 的入口,先判断会话是否已落库(BUG-989 的「第一问才落库」)。
|
||||
- 相关记录:BUG-989、BUG-928。
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-1260 | D5/D6/D8/D11 分盘映射与 PVR 6.2 不一致
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-10-07
|
||||
- 最近更新:2026-10-07
|
||||
- 影响面:`scripts/varga.py`、`scripts/divisional_charts_extended.py`;普通对话健康卡(D6/D8)、财富卡(D11)、学业卡(D5)以及报告分盘表
|
||||
- 用户现象:同一张公开盘上,D5/D6/D8/D11 的太阳与月亮星座和有出处的映射不一致
|
||||
- 触发条件:计算 D5、D6、D8 或 D11
|
||||
- 根因:这四张分盘用的是无出处的奇偶偏移;扩展分盘计算器还另写了一套相同的偏移。上游 `f32472b5` 已改为 PVR Integrated Approach 6.2.5 / 6.2.6 / 6.2.8 / 6.2.11,本仓停在 10-04 对齐点,没有跟上
|
||||
- 修复:`varga_map` 按上述四节改映射(D5 奇宫白羊、水瓶、射手、双子、天秤,偶宫金牛、处女、双鱼、摩羯、天蝎;D6 奇宫从白羊、偶宫从天秤;D8 活动白羊、固定射手、变动狮子;D11 从白羊逆数起点再顺数)。扩展计算器这四张改调 `varga.calc_varga`。批量结果写入 `mapping_source`。D8 按计数规则,不采用原书例题收束句里与计数矛盾的星座
|
||||
- 验证:`tests/test_varga_bphs.py` 手算例与既有 D11 断言;`tests/test_divisional_charts_extended.py` 委托断言
|
||||
- 防复发:上述手算例(11° 双子、19° 天蝎等)锁住四张分盘的目标星座
|
||||
- 相关记录:BUG-1261
|
||||
- 复发自:无
|
||||
- 修复版本:本分支待发布
|
||||
|
||||
@@ -159,6 +159,14 @@ class DivisionalChartsCalculator:
|
||||
Returns:
|
||||
分盘中的黄道度数(0-360)
|
||||
"""
|
||||
# D5/D6/D8/D11 share the sourced PVR mapping in varga.calc_varga.
|
||||
if division in (5, 6, 8, 11):
|
||||
try:
|
||||
from varga import calc_varga
|
||||
except ImportError:
|
||||
from scripts.varga import calc_varga
|
||||
point = calc_varga(degree, division)
|
||||
return point['sign_idx'] * 30 + point['degree_in_sign']
|
||||
# 获取星座索引和星座内度数
|
||||
sign_index = int(degree // 30)
|
||||
sign_degree = degree % 30
|
||||
@@ -445,44 +453,20 @@ class DivisionalChartsCalculator:
|
||||
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
|
||||
"""PVR 6.2.5 mapping shared with varga.calc_varga."""
|
||||
return self._calculate_varga_position(sign_index * 30 + sign_degree, 5)
|
||||
|
||||
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
|
||||
"""PVR 6.2.6 mapping shared with varga.calc_varga."""
|
||||
return self._calculate_varga_position(sign_index * 30 + sign_degree, 6)
|
||||
|
||||
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
|
||||
"""PVR 6.2.8 mapping shared with varga.calc_varga."""
|
||||
return self._calculate_varga_position(sign_index * 30 + sign_degree, 8)
|
||||
|
||||
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
|
||||
"""PVR 6.2.11 mapping shared with varga.calc_varga."""
|
||||
return self._calculate_varga_position(sign_index * 30 + sign_degree, 11)
|
||||
|
||||
def _calculate_generic_varga(self, sign_index: int, sign_degree: float, division: int) -> float:
|
||||
"""通用分盘算法(适用于其他分盘)"""
|
||||
|
||||
+10
-5
@@ -69,10 +69,11 @@ def varga_map(si, pi, div):
|
||||
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 # Drekkana: same → +4 → +8, no odd/even distinction
|
||||
if div==4: return (si+pi*3)%12
|
||||
if div==5: return (si+pi)%12 if o else (si+8+pi)%12
|
||||
if div==6: return (si+pi)%12 if o else (si+6+pi)%12
|
||||
# PVR Integrated Approach 6.2.5 / 6.2.6 / 6.2.8. D8 start is movable Aries, fixed Sagittarius, dual Leo.
|
||||
if div==5: return ((0,10,8,2,6) if o else (1,5,11,9,7))[pi]
|
||||
if div==6: return ((0 if o else 6)+pi)%12
|
||||
if div==7: return (si+pi)%12 if o else (si+6+pi)%12
|
||||
if div==8: return (si+pi)%12 if o else (si+8+pi)%12
|
||||
if div==8: return ((0,8,4)[si%3]+pi)%12
|
||||
if div==9:
|
||||
# BPHS Navamsa: movable=same, fixed=9th from sign (+8), dual=5th from sign (+4)
|
||||
if si%3==0: start=si
|
||||
@@ -80,7 +81,7 @@ def varga_map(si, pi, div):
|
||||
else: start=(si+4)%12
|
||||
return (start+pi)%12
|
||||
if div==10: return (si+pi)%12 if o else (si+8+pi)%12 # D10: even signs count from 9th inclusively => +8 offset
|
||||
if div==11: return (si+pi)%12 if o else (si+8+pi)%12 # D11 Rudramsa: mirror extended calculator
|
||||
if div==11: return (-si+pi)%12 # PVR Integrated Approach 6.2.11: anti-zodiacal seed from Aries, then zodiacal parts
|
||||
if div==12: return (si+pi)%12
|
||||
if div==16: return ((0 if o else 4)+pi)%12 # D16: movable=+0, fixed=+4; dual needs separate (2026-05-03 fix: was +1)
|
||||
if div==20: return ((0 if o else 8)+pi)%12
|
||||
@@ -323,7 +324,11 @@ def calc_all_vargas(planet_lons, asc_lon, divisions=None, mode='classical_local'
|
||||
)
|
||||
vd={'_meta':{'div':div,'name':m.get('name',''),'cn':m.get('cn',''),
|
||||
'area':m.get('area',''),'part_size':30.0/div,
|
||||
'mapping_status': mapping_status}}
|
||||
'mapping_status': mapping_status,
|
||||
'mapping_source': (
|
||||
'PVR Integrated Approach sections 6.2.5-6.2.11; D8 movable Aries, fixed Sagittarius, dual Leo'
|
||||
if div in (5, 6, 8, 11) else mapping_status
|
||||
)}}
|
||||
vd['Ascendant']=normalize_varga_ascendant(calc_varga(asc_lon,div,mode=mode))
|
||||
for pn,lon in planet_lons.items():
|
||||
vd[pn]=calc_varga(lon,div,mode=mode)
|
||||
|
||||
@@ -306,3 +306,23 @@ def test_d30_even_sign_venus_region():
|
||||
"""Even sign, 0-5° → Taurus (Venus region)."""
|
||||
lon = calc._calculate_varga_position(32.0, 30) # Taurus 2°
|
||||
assert int(lon // 30) == 1 # Taurus
|
||||
|
||||
|
||||
def test_extended_d5_d6_d8_d11_use_pvr_mapping():
|
||||
"""Extended charts delegate D5/D6/D8/D11 to the sourced varga mapping."""
|
||||
from varga import calc_varga
|
||||
|
||||
samples = (
|
||||
(5, 60 + 11, 10), # 11° Gemini -> Aquarius
|
||||
(6, 60 + 11, 2), # 11° Gemini -> Gemini
|
||||
(6, 210 + 19, 9), # 19° Scorpio -> Capricorn
|
||||
(8, 60 + 10, 6), # 10° Gemini -> Libra
|
||||
(8, 210 + 19, 1), # 19° Scorpio -> Taurus
|
||||
(11, 60 + 11, 2), # 11° Gemini -> Gemini
|
||||
(11, 210 + 19, 11), # 19° Scorpio -> Pisces
|
||||
)
|
||||
for division, degree, sign_idx in samples:
|
||||
lon = calc._calculate_varga_position(degree, division)
|
||||
point = calc_varga(degree, division)
|
||||
assert int(lon // 30) == sign_idx
|
||||
assert lon == pytest.approx(point["sign_idx"] * 30 + point["degree_in_sign"])
|
||||
|
||||
@@ -99,10 +99,13 @@ def test_varga_map_boundary_examples() -> None:
|
||||
def test_rudramsa_d11_is_supported_by_native_varga_map() -> None:
|
||||
assert varga_map(0, 0, 11) == 0
|
||||
assert varga_map(0, 10, 11) == 10
|
||||
assert varga_map(1, 0, 11) == 9
|
||||
assert varga_map(1, 10, 11) == 7
|
||||
# 原值: varga_map(1, 0, 11) == 9;varga_map(1, 10, 11) == 7;calc_varga(35) == Aquarius
|
||||
# 新值: 11、9、Aries
|
||||
# 原因: BUG-1260,D11 改按 PVR 6.2.11 从白羊逆数起点,再顺数各份
|
||||
assert varga_map(1, 0, 11) == 11
|
||||
assert varga_map(1, 10, 11) == 9
|
||||
result = calc_varga(35.0, 11)
|
||||
assert result["sign"] == "Aquarius"
|
||||
assert result["sign"] == "Aries"
|
||||
assert 0 <= result["degree_in_sign"] < 30
|
||||
|
||||
|
||||
@@ -117,7 +120,29 @@ def test_default_varga_batch_includes_declared_vargas() -> None:
|
||||
charts = calc_all_vargas({"Moon": 35.0}, 10.0)
|
||||
for key in ("D5_Panchamsa", "D6_Shashthamsa", "D8_Ashtamsa", "D11_Rudramsa", "D81_Navamsa-Navamsa", "D108_Dwadasamsa-Navamsa", "D144_Dwadasamsa-Dwadasamsa"):
|
||||
assert key in charts
|
||||
assert charts["D11_Rudramsa"]["Moon"]["sign"] == "Aquarius"
|
||||
# 原值: Aquarius / 新值: Aries / 原因: BUG-1260,35° 的 D11 按 PVR 6.2.11 落到白羊
|
||||
assert charts["D11_Rudramsa"]["Moon"]["sign"] == "Aries"
|
||||
assert "6.2.5" in charts["D5_Panchamsa"]["_meta"]["mapping_source"]
|
||||
assert "6.2.11" in charts["D11_Rudramsa"]["_meta"]["mapping_source"]
|
||||
|
||||
|
||||
def test_pvr_d5_d6_d8_d11_worked_examples() -> None:
|
||||
"""Hand counts from PVR Integrated Approach 6.2.5 / 6.2.6 / 6.2.8 / 6.2.11."""
|
||||
# 6.2.5: odd parts Ar, Aq, Sg, Ge, Li; even Ta, Vi, Pi, Cp, Sc.
|
||||
# 11° Gemini is the 2nd part of an odd sign.
|
||||
assert calc_varga(60 + 11, 5)["sign"] == "Aquarius"
|
||||
# 19° Taurus is the 4th part of an even sign.
|
||||
assert calc_varga(30 + 19, 5)["sign"] == "Capricorn"
|
||||
# 6.2.6: 11° Gemini -> Gemini; 19° Scorpio -> Capricorn.
|
||||
assert calc_varga(60 + 11, 6)["sign"] == "Gemini"
|
||||
assert calc_varga(210 + 19, 6)["sign"] == "Capricorn"
|
||||
# 6.2.8 counting: 10° Gemini is the 3rd part of a dual sign, 3rd from Leo is Libra.
|
||||
# 19° Scorpio is the 6th part of a fixed sign, 6th from Sagittarius is Taurus.
|
||||
assert calc_varga(60 + 10, 8)["sign"] == "Libra"
|
||||
assert calc_varga(210 + 19, 8)["sign"] == "Taurus"
|
||||
# 6.2.11: 11° Gemini -> Gemini; 19° Scorpio -> Pisces.
|
||||
assert calc_varga(60 + 11, 11)["sign"] == "Gemini"
|
||||
assert calc_varga(210 + 19, 11)["sign"] == "Pisces"
|
||||
|
||||
|
||||
def test_navamsa_matches_user_jhora_pdf_reference_chart() -> None:
|
||||
|
||||
Reference in New Issue
Block a user