fix(dasha): measure nakshatra index and progress on one grid
Upstream 3c2dad95, 8643bc9a, and the lon_to_nakshatra part of 9e04f0db. Exact star starts were split across int-division and modulo, so 16 of 27 openings reported a zero balance and skipped the mahadasha. Off-boundary longitudes keep the old modulo. BUG-1381. Co-Authored-By: Grok (agent loop) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Grok (agent loop)
Cursor
parent
68762ccec5
commit
d11ee6f0dd
@@ -68,12 +68,18 @@ def fuzzy_match_nakshatra(name):
|
||||
return None
|
||||
|
||||
def lon_to_nakshatra(moon_lon):
|
||||
"""月亮黄经(0-360)→ Nakshatra + Pada"""
|
||||
nak_span = 360 / 27
|
||||
pada_span = nak_span / 4
|
||||
idx = int(moon_lon / nak_span)
|
||||
progress = (moon_lon % nak_span) / nak_span
|
||||
pada = int((moon_lon % nak_span) / pada_span) + 1
|
||||
"""月亮黄经(0-360)→ Nakshatra + Pada。序号与进度来自同一把尺子。"""
|
||||
try:
|
||||
from nakshatra_advanced import nakshatra_index_and_progress
|
||||
except ImportError:
|
||||
from scripts.nakshatra_advanced import nakshatra_index_and_progress
|
||||
idx, progress = nakshatra_index_and_progress(moon_lon)
|
||||
if progress == 0.0:
|
||||
pada = 1
|
||||
else:
|
||||
nak_span = 360 / 27
|
||||
pada_span = nak_span / 4
|
||||
pada = int((float(moon_lon) % nak_span) / pada_span) + 1
|
||||
return NAKSHATRA_LIST[idx], progress, pada
|
||||
|
||||
def build_dasha_timeline(birth_date_str, nak_info, nak_progress):
|
||||
|
||||
+29
-11
@@ -12023,10 +12023,16 @@ def _load_strict_evidence_collector():
|
||||
# ============================================================================
|
||||
def _nakshatra_fields(sidereal_lon):
|
||||
"""Nakshatra, pada and lord of a sidereal longitude — planets and the ascendant alike."""
|
||||
nak_span = 360.0 / 27
|
||||
from nakshatra_advanced import nakshatra_index_and_progress
|
||||
lon = sidereal_lon % 360
|
||||
pada = int((lon % nak_span) / (nak_span / 4)) + 1
|
||||
name, lord, _ = NAKSHATRA_LIST[int(lon / nak_span) % 27]
|
||||
idx, progress = nakshatra_index_and_progress(lon)
|
||||
if progress == 0.0:
|
||||
pada = 1
|
||||
else:
|
||||
nak_span = 360.0 / 27
|
||||
pada = int((lon % nak_span) / (nak_span / 4)) + 1
|
||||
idx = int(lon / nak_span) % 27
|
||||
name, lord, _ = NAKSHATRA_LIST[idx]
|
||||
return {"nakshatra": name, "nakshatra_pada": pada, "nakshatra_lord": lord}
|
||||
|
||||
|
||||
@@ -12165,8 +12171,9 @@ def _build_pratyantar_timeline(md_lord, ad_lord, ad_start, ad_end, reference_dt=
|
||||
def cmd_dasha(args):
|
||||
nak_info = None; progress = 0.5
|
||||
if args.moon_lon is not None:
|
||||
ns = 360.0 / 27; idx = int(args.moon_lon / ns); progress = (args.moon_lon % ns) / ns
|
||||
nak_info = NAKSHATRA_LIST[idx % 27]
|
||||
from nakshatra_advanced import nakshatra_index_and_progress
|
||||
idx, progress = nakshatra_index_and_progress(args.moon_lon)
|
||||
nak_info = NAKSHATRA_LIST[idx]
|
||||
elif args.nakshatra:
|
||||
nl = args.nakshatra.lower().replace(" ", "").replace("-", "")
|
||||
for n in NAKSHATRA_LIST:
|
||||
@@ -12183,8 +12190,9 @@ def cmd_dasha(args):
|
||||
moon_lon = moon.get("degree_raw")
|
||||
if moon_lon is None:
|
||||
return {"error": "无法计算Moon位置"}
|
||||
ns = 360.0 / 27; idx = int(moon_lon / ns); progress = (moon_lon % ns) / ns
|
||||
nak_info = NAKSHATRA_LIST[idx % 27]
|
||||
from nakshatra_advanced import nakshatra_index_and_progress
|
||||
idx, progress = nakshatra_index_and_progress(moon_lon)
|
||||
nak_info = NAKSHATRA_LIST[idx]
|
||||
|
||||
nak_name, start_lord, start_years = nak_info
|
||||
birthdate = args.birthdate or f"{args.year}-{args.month:02d}-{args.day:02d}"
|
||||
@@ -15425,10 +15433,15 @@ def cmd_full_reading(args):
|
||||
try:
|
||||
moon_data = planets.get('Moon', {})
|
||||
moon_lon = moon_data.get('degree_raw', moon_data.get('degree', 0))
|
||||
nak_idx = int(moon_lon / (360 / 27)) % 27
|
||||
from nakshatra_advanced import nakshatra_index_and_progress
|
||||
nak_idx, nak_progress = nakshatra_index_and_progress(moon_lon)
|
||||
if nak_progress != 0.0:
|
||||
nak_idx = int(moon_lon / (360 / 27)) % 27
|
||||
pada = int((moon_lon % (360/27)) / (360/108)) + 1
|
||||
else:
|
||||
pada = 1
|
||||
nak_name = NAKSHATRA_LIST[nak_idx][0]
|
||||
nak_lord = NAKSHATRA_LIST[nak_idx][1]
|
||||
pada = int((moon_lon % (360/27)) / (360/108)) + 1
|
||||
|
||||
birthdate = f"{args.year}-{args.month:02d}-{args.day:02d}"
|
||||
today_str = getattr(args, 'transit_date', None) or getattr(args, 'today', None) or datetime.now().strftime('%Y-%m-%d')
|
||||
@@ -16459,8 +16472,13 @@ def cmd_full_reading(args):
|
||||
jaimini_data = report['modules'].get('jaimini', {})
|
||||
chara_dasha_data = jaimini_data.get('chara_dasha', {}) if isinstance(jaimini_data, dict) else {}
|
||||
moon_lon = planet_lons.get('Moon', 0)
|
||||
moon_nakshatra_index = int(moon_lon / (360 / 27)) % 27
|
||||
moon_pada = int((moon_lon % (360 / 27)) / (360 / 108)) + 1
|
||||
from nakshatra_advanced import nakshatra_index_and_progress
|
||||
moon_nakshatra_index, moon_nak_progress = nakshatra_index_and_progress(moon_lon)
|
||||
if moon_nak_progress != 0.0:
|
||||
moon_nakshatra_index = int(moon_lon / (360 / 27)) % 27
|
||||
moon_pada = int((moon_lon % (360 / 27)) / (360 / 108)) + 1
|
||||
else:
|
||||
moon_pada = 1
|
||||
tithi_number = int(((moon_lon - planet_lons.get('Sun', 0)) % 360) / 12) + 1
|
||||
birth_dt = _birth_datetime_from_args(args)
|
||||
ll_name = SIGN_LORDS[SIGNS[asc_idx]]
|
||||
|
||||
@@ -16,6 +16,14 @@ Nakshatra深度分析系统
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
import math
|
||||
from datetime import datetime, timedelta
|
||||
from bisect import bisect_right
|
||||
from fractions import Fraction
|
||||
|
||||
# Exact star openings. float(Fraction) is the grid cmd_dasha must share with
|
||||
# lon_to_nakshatra; 360/27 and modulo disagree at several of these points.
|
||||
_NAK_SPAN = Fraction(40, 3)
|
||||
_NAK_STARTS = tuple(float(_NAK_SPAN * index) for index in range(27))
|
||||
_NAK_SPAN_FLOAT = 360.0 / 27.0
|
||||
|
||||
NAK_LIST = [
|
||||
("Ashwini","Ketu",7),("Bharani","Venus",20),("Krittika","Sun",6),
|
||||
@@ -53,15 +61,42 @@ NAK_ELEMENT = {
|
||||
}
|
||||
|
||||
|
||||
def nakshatra_index_and_progress(longitude: float) -> Tuple[int, float]:
|
||||
"""星宿序号和已用比例,由同一把尺子量出。
|
||||
|
||||
经度恰好等于某星宿起点时,这一点属于刚开始的那一宿,已用比例为 0。
|
||||
其余经度保持原来的取模结果,避免改动非边界点。
|
||||
"""
|
||||
lon = float(longitude) % 360.0
|
||||
idx = bisect_right(_NAK_STARTS, lon) - 1
|
||||
if idx < 0:
|
||||
idx = 0
|
||||
elif idx > 26:
|
||||
idx = 26
|
||||
if lon == _NAK_STARTS[idx]:
|
||||
return idx, 0.0
|
||||
legacy_idx = int(lon / _NAK_SPAN_FLOAT) % 27
|
||||
legacy_progress = (lon % _NAK_SPAN_FLOAT) / _NAK_SPAN_FLOAT
|
||||
return legacy_idx, legacy_progress
|
||||
|
||||
|
||||
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
|
||||
idx, _progress = nakshatra_index_and_progress(longitude)
|
||||
lon = float(longitude) % 360.0
|
||||
if lon == _NAK_STARTS[idx]:
|
||||
nak_idx = idx
|
||||
deg_in_nak = 0.0
|
||||
pada = 1
|
||||
deg_in_pada = 0.0
|
||||
else:
|
||||
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],
|
||||
@@ -126,11 +161,13 @@ def calc_vimshottari_start(moon_longitude: float) -> Dict:
|
||||
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
|
||||
# 已用比例与星宿序号来自同一把尺子。起点处必须是 0,不能是「几乎走完」。
|
||||
_, used_ratio = nakshatra_index_and_progress(moon_longitude)
|
||||
if float(moon_longitude) % 360.0 != _NAK_STARTS[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的剩余年数
|
||||
|
||||
Reference in New Issue
Block a user