feat: 完善日月食与月掩几何链路并扩展历法接口
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑 - 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口 - 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界 - 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名 - 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验 - 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口 - 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
This commit is contained in:
@@ -91,3 +91,140 @@ func TestSharedObservationRejectsNonFiniteQuery(t *testing.T) {
|
||||
t.Fatalf("StarRiseTime error = %v, want ErrInvalidObservationInput", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoonMaximumDeclinationEventsRejectNonFiniteQuery(t *testing.T) {
|
||||
nonFinite := []struct {
|
||||
name string
|
||||
jd float64
|
||||
}{
|
||||
{"NaN", math.NaN()},
|
||||
{"+Inf", math.Inf(1)},
|
||||
{"-Inf", math.Inf(-1)},
|
||||
}
|
||||
events := []struct {
|
||||
name string
|
||||
fn func(float64) DeclinationEvent
|
||||
}{
|
||||
{"LastMoonMaximumNorthDeclination", LastMoonMaximumNorthDeclination},
|
||||
{"NextMoonMaximumNorthDeclination", NextMoonMaximumNorthDeclination},
|
||||
{"ClosestMoonMaximumNorthDeclination", ClosestMoonMaximumNorthDeclination},
|
||||
{"LastMoonMaximumSouthDeclination", LastMoonMaximumSouthDeclination},
|
||||
{"NextMoonMaximumSouthDeclination", NextMoonMaximumSouthDeclination},
|
||||
{"ClosestMoonMaximumSouthDeclination", ClosestMoonMaximumSouthDeclination},
|
||||
}
|
||||
for _, event := range events {
|
||||
for _, query := range nonFinite {
|
||||
// A non-finite query used to seed an out-of-range cycle index and spin in the
|
||||
// sampling sweep forever; it must return the zero event instead.
|
||||
got := event.fn(query.jd)
|
||||
if got.JDE != 0 || got.Declination != 0 {
|
||||
t.Fatalf("%s(%s) = %+v, want zero event", event.name, query.name, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The finite path must keep working.
|
||||
const jd = 2460310.5
|
||||
north := NextMoonMaximumNorthDeclination(jd)
|
||||
if !(north.JDE > jd) || north.Declination == 0 {
|
||||
t.Fatalf("NextMoonMaximumNorthDeclination(%v) = %+v, want a later event", jd, north)
|
||||
}
|
||||
south := LastMoonMaximumSouthDeclination(jd)
|
||||
if !(south.JDE <= jd) || south.Declination == 0 {
|
||||
t.Fatalf("LastMoonMaximumSouthDeclination(%v) = %+v, want an earlier event", jd, south)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOuterPlanetStationEventsRejectNonFiniteQuery(t *testing.T) {
|
||||
nonFinite := []struct {
|
||||
name string
|
||||
jd float64
|
||||
}{
|
||||
{"NaN", math.NaN()},
|
||||
{"+Inf", math.Inf(1)},
|
||||
{"-Inf", math.Inf(-1)},
|
||||
}
|
||||
events := []struct {
|
||||
name string
|
||||
fn func(float64) float64
|
||||
}{
|
||||
{"Mercury", NextMercuryProgradeToRetrograde},
|
||||
{"Mercury retrograde", NextMercuryRetrograde},
|
||||
{"Venus", NextVenusProgradeToRetrograde},
|
||||
{"Venus retrograde", NextVenusRetrograde},
|
||||
{"Mars", NextMarsProgradeToRetrograde},
|
||||
{"Jupiter", NextJupiterProgradeToRetrograde},
|
||||
{"Saturn", NextSaturnProgradeToRetrograde},
|
||||
{"Uranus", NextUranusProgradeToRetrograde},
|
||||
{"Neptune", NextNeptuneProgradeToRetrograde},
|
||||
{"Mars opposition", NextMarsOpposition},
|
||||
{"Jupiter opposition", NextJupiterOpposition},
|
||||
{"Saturn opposition", NextSaturnOpposition},
|
||||
{"Uranus opposition", NextUranusOpposition},
|
||||
{"Neptune opposition", NextNeptuneOpposition},
|
||||
{"Mars eastern quadrature", NextMarsEasternQuadrature},
|
||||
{"Jupiter eastern quadrature", NextJupiterEasternQuadrature},
|
||||
{"Saturn eastern quadrature", NextSaturnEasternQuadrature},
|
||||
{"Uranus eastern quadrature", NextUranusEasternQuadrature},
|
||||
{"Neptune eastern quadrature", NextNeptuneEasternQuadrature},
|
||||
}
|
||||
for _, event := range events {
|
||||
for _, query := range nonFinite {
|
||||
if got := event.fn(query.jd); !math.IsNaN(got) {
|
||||
t.Fatalf("%s(%s) = %v, want NaN", event.name, query.name, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOuterPlanetLastStationEventsRejectNonFiniteQuery(t *testing.T) {
|
||||
events := []struct {
|
||||
name string
|
||||
fn func(float64) float64
|
||||
}{
|
||||
{"LastMarsProgradeToRetrograde", LastMarsProgradeToRetrograde},
|
||||
{"LastMarsRetrogradeToPrograde", LastMarsRetrogradeToPrograde},
|
||||
{"LastJupiterProgradeToRetrograde", LastJupiterProgradeToRetrograde},
|
||||
{"LastJupiterRetrogradeToPrograde", LastJupiterRetrogradeToPrograde},
|
||||
{"LastSaturnProgradeToRetrograde", LastSaturnProgradeToRetrograde},
|
||||
{"LastSaturnRetrogradeToPrograde", LastSaturnRetrogradeToPrograde},
|
||||
{"LastUranusProgradeToRetrograde", LastUranusProgradeToRetrograde},
|
||||
{"LastUranusRetrogradeToPrograde", LastUranusRetrogradeToPrograde},
|
||||
{"LastNeptuneProgradeToRetrograde", LastNeptuneProgradeToRetrograde},
|
||||
{"LastNeptuneRetrogradeToPrograde", LastNeptuneRetrogradeToPrograde},
|
||||
}
|
||||
for _, event := range events {
|
||||
if got := event.fn(math.NaN()); !math.IsNaN(got) {
|
||||
t.Fatalf("%s(NaN) = %v, want NaN", event.name, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询落在事件之后 1 秒:首候选必须被侧向不变量拒绝,第二候选也必须通过同一不变量。
|
||||
func TestOuterPlanetStationSecondCandidateKeepsSideInvariant(t *testing.T) {
|
||||
const offsetSeconds = 1.0
|
||||
cases := []struct {
|
||||
name string
|
||||
fn func(float64) float64
|
||||
}{
|
||||
{"Mars", NextMarsProgradeToRetrograde},
|
||||
{"Jupiter", NextJupiterProgradeToRetrograde},
|
||||
{"Saturn", NextSaturnProgradeToRetrograde},
|
||||
{"Uranus", NextUranusProgradeToRetrograde},
|
||||
{"Neptune", NextNeptuneProgradeToRetrograde},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
event := tc.fn(JDECalc(2025, 1, 1))
|
||||
if math.IsNaN(event) {
|
||||
t.Fatalf("%s: no station event found", tc.name)
|
||||
}
|
||||
query := event + offsetSeconds/86400.0
|
||||
got := tc.fn(TD2UT(query, true))
|
||||
if math.IsNaN(got) {
|
||||
t.Fatalf("%s: second candidate rejected as NaN at %s", tc.name, JDE2Date(query))
|
||||
}
|
||||
if got < query-stationQueryToleranceUT {
|
||||
t.Fatalf("%s: returned %.9f before the query %.9f", tc.name, got, query)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user