feat: 完善日月食与月掩几何链路并扩展历法接口
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑 - 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口 - 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界 - 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名 - 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验 - 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口 - 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 本文件钉住月出/月落「缺失事件」的口径:错误名描述缺失的那个现象,不描述被问的事件。
|
||||
|
||||
func moonRiseSetErrorMatches(got, want error) bool {
|
||||
if want == nil {
|
||||
return got == nil
|
||||
}
|
||||
return errors.Is(got, want)
|
||||
}
|
||||
|
||||
func moonRiseSetDailyGeometry(jd, lon, lat, tz float64) (aboveAll, belowAll bool) {
|
||||
dayStart := math.Floor(jd) + 0.5
|
||||
aboveAll, belowAll = true, true
|
||||
previous := moonRiseSetResidual(dayStart, lon, lat, tz, 1, 0, -1)
|
||||
for i := 1; i <= 288; i++ {
|
||||
current := moonRiseSetResidual(dayStart+float64(i)/288.0, lon, lat, tz, 1, 0, -1)
|
||||
if previous <= 0 || current <= 0 {
|
||||
aboveAll = false
|
||||
}
|
||||
if previous >= 0 || current >= 0 {
|
||||
belowAll = false
|
||||
}
|
||||
previous = current
|
||||
}
|
||||
return aboveAll, belowAll
|
||||
}
|
||||
|
||||
func TestMoonRiseSetMissingEventConvention(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
jd float64
|
||||
lon, lat, tz float64
|
||||
riseErr, setErr error
|
||||
}{
|
||||
{"极昼:全天在地平线上", JDECalc(2023, 6, 21), 0, 85, 0, ErrNeverSet, ErrNeverSet},
|
||||
{"极夜:全天在地平线下", JDECalc(2023, 12, 22), 0, -85, 0, ErrNeverRise, ErrNeverRise},
|
||||
{"当日无升起但别日有", JDECalc(2024, 2, 29), 0, 60, 0, ErrNotOnThisDate, nil},
|
||||
{"正常日两侧都有", JDECalc(2025, 6, 5), 116.4074, 39.9042, 8, nil, nil},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if _, err := GetMoonRiseTime(tc.jd, tc.lon, tc.lat, tc.tz, 1, 0); !moonRiseSetErrorMatches(err, tc.riseErr) {
|
||||
t.Fatalf("GetMoonRiseTime error = %v, want %v", err, tc.riseErr)
|
||||
}
|
||||
if _, err := GetMoonSetTime(tc.jd, tc.lon, tc.lat, tc.tz, 1, 0); !moonRiseSetErrorMatches(err, tc.setErr) {
|
||||
t.Fatalf("GetMoonSetTime error = %v, want %v", err, tc.setErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoonRiseSetMissingEventMatchesDailyGeometry(t *testing.T) {
|
||||
dates := []float64{
|
||||
JDECalc(2023, 6, 21), JDECalc(2023, 12, 22), JDECalc(2024, 2, 29),
|
||||
JDECalc(2025, 6, 21), JDECalc(2025, 12, 22), JDECalc(2026, 3, 3),
|
||||
}
|
||||
latitudes := []float64{-89, -85, -75, -66, -60, 60, 66, 75, 85, 89}
|
||||
for _, jd := range dates {
|
||||
for _, lat := range latitudes {
|
||||
aboveAll, belowAll := moonRiseSetDailyGeometry(jd, 0, lat, 0)
|
||||
if !aboveAll && !belowAll {
|
||||
continue
|
||||
}
|
||||
_, riseErr := GetMoonRiseTime(jd, 0, lat, 0, 1, 0)
|
||||
_, setErr := GetMoonSetTime(jd, 0, lat, 0, 1, 0)
|
||||
want := ErrNeverSet
|
||||
if belowAll {
|
||||
want = ErrNeverRise
|
||||
}
|
||||
if !moonRiseSetErrorMatches(riseErr, want) {
|
||||
t.Fatalf("lat %v jd %.1f aboveAll=%v belowAll=%v: moonrise error = %v, want %v",
|
||||
lat, jd, aboveAll, belowAll, riseErr, want)
|
||||
}
|
||||
if !moonRiseSetErrorMatches(setErr, want) {
|
||||
t.Fatalf("lat %v jd %.1f aboveAll=%v belowAll=%v: moonset error = %v, want %v",
|
||||
lat, jd, aboveAll, belowAll, setErr, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user