feat: 完善日月食与月掩几何链路并扩展历法接口
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑 - 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口 - 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界 - 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名 - 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验 - 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口 - 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
This commit is contained in:
@@ -6,6 +6,10 @@ const (
|
||||
eventNewtonMaxIterations = 24
|
||||
eventDirectionalSearchIterations = 128
|
||||
eventRiseSetScanStep = 1.0 / 1440
|
||||
// stationDerivativeStepDay 「留」精修用的中心差分步长(天)。
|
||||
// 0.5 秒级的步长会被浮点相消噪声支配(实测外行星留误差可达 42 s);
|
||||
// 0.01 天(14.4 分钟)实测误差 <0.05 s,且求值次数不变。
|
||||
stationDerivativeStepDay = 0.01
|
||||
)
|
||||
|
||||
func isFiniteFloat(value float64) bool {
|
||||
@@ -121,6 +125,56 @@ func eventDirectionalBracketRefine(leftJD, rightJD, leftValue, rightValue float6
|
||||
return (leftJD + rightJD) / 2
|
||||
}
|
||||
|
||||
// eventBracketSecantRoot 在已知异号的括号内用割线法(带中点兜底)求根。
|
||||
//
|
||||
// 与 eventDirectionalBracketRefine(固定 48 次二分)相比,割线法通常 5~8 次求值即可达到
|
||||
// 亚秒精度,适合「括号由廉价截断级数给出、抛光必须用全项级数」的两段式搜索。
|
||||
// 括号每一步都收缩,因此不会跑到括号外;括号端点同号或出现非有限值时返回 false。
|
||||
func eventBracketSecantRoot(leftJD, rightJD, leftValue, rightValue, tolerance float64,
|
||||
fn func(float64) float64) (float64, bool) {
|
||||
if leftValue == 0 {
|
||||
return leftJD, true
|
||||
}
|
||||
if rightValue == 0 {
|
||||
return rightJD, true
|
||||
}
|
||||
if !isFiniteFloat(leftValue) || !isFiniteFloat(rightValue) || leftValue*rightValue > 0 {
|
||||
return math.NaN(), false
|
||||
}
|
||||
if !isFiniteFloat(tolerance) || tolerance <= 0 {
|
||||
tolerance = 0.5 / 86400.0
|
||||
}
|
||||
bestJD := (leftJD + rightJD) / 2
|
||||
for i := 0; i < 48; i++ {
|
||||
candidateJD := (leftJD + rightJD) / 2
|
||||
if rightValue != leftValue {
|
||||
secantJD := rightJD - rightValue*(rightJD-leftJD)/(rightValue-leftValue)
|
||||
if secantJD > leftJD && secantJD < rightJD {
|
||||
candidateJD = secantJD
|
||||
}
|
||||
}
|
||||
candidateValue := fn(candidateJD)
|
||||
if !isFiniteFloat(candidateValue) {
|
||||
return math.NaN(), false
|
||||
}
|
||||
bestJD = candidateJD
|
||||
if candidateValue == 0 || math.Abs(rightJD-leftJD) <= tolerance {
|
||||
return candidateJD, true
|
||||
}
|
||||
if (leftValue < 0) == (candidateValue < 0) {
|
||||
leftJD, leftValue = candidateJD, candidateValue
|
||||
continue
|
||||
}
|
||||
rightJD, rightValue = candidateJD, candidateValue
|
||||
}
|
||||
if math.Abs(rightJD-leftJD) <= tolerance {
|
||||
return bestJD, true
|
||||
}
|
||||
// 48 次迭代后括号仍宽于容差(例如容差低于该儒略日的 ULP):调用方把 ok 当作
|
||||
// “已抛光到容差”,这里必须报 false,不能返回一个精度未达标的时刻。
|
||||
return bestJD, false
|
||||
}
|
||||
|
||||
func eventFixedScanRefine(seed, halfWindow, step float64, fn func(float64) float64) float64 {
|
||||
start := seed - halfWindow
|
||||
bestJD := start
|
||||
|
||||
Reference in New Issue
Block a user