feat: 完善日月食与月掩几何链路并扩展历法接口
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑 - 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口 - 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界 - 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名 - 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验 - 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口 - 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package basic
|
||||
|
||||
import "testing"
|
||||
|
||||
// 批量入口是导出契约的一部分,必须与逐时刻入口给出同一条数值链。
|
||||
func TestSolarEclipseShadowBatchEntriesMatchPerInstantCalls(t *testing.T) {
|
||||
footprints := SolarEclipsePartialFootprints(JDECalc(2009, 7, 22), SolarEclipsePartialFootprintOptions{
|
||||
StepDays: 6.0 / 1440.0, BoundaryPoints: 48, DisableRiseSetCurves: true,
|
||||
CentralShadowStepDays: 6.0 / 1440.0,
|
||||
})
|
||||
if len(footprints.CentralShadowFootprints) < 3 {
|
||||
t.Fatalf("central shadow samples=%d, want a full series", len(footprints.CentralShadowFootprints))
|
||||
}
|
||||
options := SolarEclipseShadowSolverOptions{}
|
||||
step := 6.0 / 1440.0
|
||||
start := footprints.CentralShadowFootprints[0].JDE
|
||||
end := start + 4*step
|
||||
batch := SolarEclipseShadowBetweenJDE(start, end, step, options)
|
||||
if len(batch) != 5 {
|
||||
t.Fatalf("batch length=%d, want 5", len(batch))
|
||||
}
|
||||
nonEmpty := 0
|
||||
for index, instant := range batch {
|
||||
direct, ok := SolarEclipseShadowAtJDE(start+float64(index)*step, options)
|
||||
if ok != !direct.Empty() {
|
||||
t.Fatalf("instant %d ok=%v, Empty=%v", index, ok, direct.Empty())
|
||||
}
|
||||
if instant.Empty() != direct.Empty() || len(instant.Boundaries) != len(direct.Boundaries) {
|
||||
t.Fatalf("instant %d batch=%d segments, direct=%d", index, len(instant.Boundaries), len(direct.Boundaries))
|
||||
}
|
||||
if !instant.Empty() {
|
||||
nonEmpty++
|
||||
}
|
||||
}
|
||||
if nonEmpty == 0 {
|
||||
t.Fatal("batch reported no shadow anywhere along the central path")
|
||||
}
|
||||
longitude, latitude := footprints.Eclipse.GreatestLongitude, footprints.Eclipse.GreatestLatitude
|
||||
solver := NewSolarEclipseShadowSolver(options)
|
||||
states := solver.StationStatesBetweenJDE(start, end, step, longitude, latitude, 0)
|
||||
if len(states) != len(batch) {
|
||||
t.Fatalf("station state batch length=%d, want %d", len(states), len(batch))
|
||||
}
|
||||
for index, state := range states {
|
||||
direct := SolarEclipseStationStateAtJDE(start+float64(index)*step, longitude, latitude, 0, options)
|
||||
if state != direct {
|
||||
t.Fatalf("station state %d = %+v, want %+v", index, state, direct)
|
||||
}
|
||||
}
|
||||
for _, badStep := range []float64{0, -step} {
|
||||
if got := SolarEclipseShadowBetweenJDE(start, end, badStep, options); got != nil {
|
||||
t.Fatalf("step %v produced %d instants, want nil", badStep, len(got))
|
||||
}
|
||||
}
|
||||
if got := solver.ShadowBetweenJDE(end, start, step); got != nil {
|
||||
t.Fatalf("reversed window produced %d instants, want nil", len(got))
|
||||
}
|
||||
if got := SolarEclipseShadowBetweenJDE(start, start+10, 1e-9, options); got != nil {
|
||||
t.Fatalf("oversized batch produced %d instants, want nil", len(got))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user