feat: 引入可切换星历模型并扩展天象观测链路
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
package eclipse
|
||||
|
||||
import (
|
||||
"b612.me/astro/basic"
|
||||
"b612.me/astro/internal/ephem"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type contextAPI interface {
|
||||
ClosestGeometricLocalLunarEclipse(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
ClosestGeometricLocalLunarEclipseChauvenet(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
ClosestGeometricLocalLunarEclipseDanjon(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
ClosestGeometricLocalSolarEclipse(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
ClosestGeometricLocalSolarEclipseIAUSingleK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
ClosestGeometricLocalSolarEclipseNASABulletinSplitK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
ClosestLocalAnnularSolarEclipse(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
ClosestLocalLunarEclipse(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
ClosestLocalLunarEclipseChauvenet(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
ClosestLocalLunarEclipseDanjon(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
ClosestLocalSolarEclipse(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
ClosestLocalSolarEclipseIAUSingleK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
ClosestLocalSolarEclipseNASABulletinSplitK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
ClosestLocalTotalLunarEclipse(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
ClosestLocalTotalSolarEclipse(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
ClosestLunarEclipse(date time.Time) LunarEclipseInfo
|
||||
ClosestLunarEclipseChauvenet(date time.Time) LunarEclipseInfo
|
||||
ClosestLunarEclipseDanjon(date time.Time) LunarEclipseInfo
|
||||
ClosestSolarEclipse(date time.Time) SolarEclipseInfo
|
||||
ClosestSolarEclipseIAUSingleK(date time.Time) SolarEclipseInfo
|
||||
ClosestSolarEclipseNASABulletinSplitK(date time.Time) SolarEclipseInfo
|
||||
ClosestSolarEclipseWithOptions(date time.Time, options SolarEclipseOptions) SolarEclipseInfo
|
||||
GeometricLocalLunarEclipseOnDate(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
GeometricLocalLunarEclipseOnDateChauvenet(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
GeometricLocalLunarEclipseOnDateDanjon(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
GeometricLocalSolarEclipseOnDate(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
GeometricLocalSolarEclipseOnDateIAUSingleK(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
GeometricLocalSolarEclipseOnDateNASABulletinSplitK(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
LastGeometricLocalLunarEclipse(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
LastGeometricLocalLunarEclipseChauvenet(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
LastGeometricLocalLunarEclipseDanjon(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
LastGeometricLocalSolarEclipse(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
LastGeometricLocalSolarEclipseIAUSingleK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
LastGeometricLocalSolarEclipseNASABulletinSplitK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
LastLocalAnnularSolarEclipse(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
LastLocalLunarEclipse(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
LastLocalLunarEclipseChauvenet(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
LastLocalLunarEclipseDanjon(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
LastLocalSolarEclipse(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
LastLocalSolarEclipseIAUSingleK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
LastLocalSolarEclipseNASABulletinSplitK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
LastLocalTotalLunarEclipse(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
LastLocalTotalSolarEclipse(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
LastLunarEclipse(date time.Time) LunarEclipseInfo
|
||||
LastLunarEclipseChauvenet(date time.Time) LunarEclipseInfo
|
||||
LastLunarEclipseDanjon(date time.Time) LunarEclipseInfo
|
||||
LastSolarEclipse(date time.Time) SolarEclipseInfo
|
||||
LastSolarEclipseIAUSingleK(date time.Time) SolarEclipseInfo
|
||||
LastSolarEclipseNASABulletinSplitK(date time.Time) SolarEclipseInfo
|
||||
LastSolarEclipseWithOptions(date time.Time, options SolarEclipseOptions) SolarEclipseInfo
|
||||
LocalLunarEclipseOnDate(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
LocalLunarEclipseOnDateChauvenet(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
LocalLunarEclipseOnDateDanjon(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
LocalSolarEclipseInfoInUT1(info LocalSolarEclipseInfo) LocalSolarEclipseInfo
|
||||
LocalSolarEclipseOnDate(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
LocalSolarEclipseOnDateIAUSingleK(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
LocalSolarEclipseOnDateNASABulletinSplitK(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
LocalSolarEclipseOnDateWithOptions(date time.Time, lon, lat, height float64, options SolarEclipseOptions) (LocalSolarEclipseInfo, bool)
|
||||
LunarEclipseGeocentricPanelAt(date time.Time) (LunarEclipseGeocentricPanel, bool)
|
||||
LunarEclipseGeocentricPanelChauvenet(date time.Time) (LunarEclipseGeocentricPanel, bool)
|
||||
LunarEclipseInfoInUT1(info LunarEclipseInfo) LunarEclipseInfo
|
||||
LunarEclipseOnDate(date time.Time) (LunarEclipseInfo, bool)
|
||||
LunarEclipseOnDateChauvenet(date time.Time) (LunarEclipseInfo, bool)
|
||||
LunarEclipseOnDateDanjon(date time.Time) (LunarEclipseInfo, bool)
|
||||
NewSolarEclipseShadowSolver(options SolarEclipseShadowSolverOptions) *SolarEclipseShadowSolver
|
||||
NextGeometricLocalLunarEclipse(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
NextGeometricLocalLunarEclipseChauvenet(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
NextGeometricLocalLunarEclipseDanjon(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
NextGeometricLocalSolarEclipse(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
NextGeometricLocalSolarEclipseIAUSingleK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
NextGeometricLocalSolarEclipseNASABulletinSplitK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
NextLocalAnnularSolarEclipse(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
NextLocalLunarEclipse(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
NextLocalLunarEclipseChauvenet(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
NextLocalLunarEclipseDanjon(date time.Time, lon, lat, height float64) LocalLunarEclipseInfo
|
||||
NextLocalSolarEclipse(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
NextLocalSolarEclipseIAUSingleK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
NextLocalSolarEclipseNASABulletinSplitK(date time.Time, lon, lat, height float64) LocalSolarEclipseInfo
|
||||
NextLocalTotalLunarEclipse(date time.Time, lon, lat, height float64) (LocalLunarEclipseInfo, bool)
|
||||
NextLocalTotalSolarEclipse(date time.Time, lon, lat, height float64) (LocalSolarEclipseInfo, bool)
|
||||
NextLunarEclipse(date time.Time) LunarEclipseInfo
|
||||
NextLunarEclipseChauvenet(date time.Time) LunarEclipseInfo
|
||||
NextLunarEclipseDanjon(date time.Time) LunarEclipseInfo
|
||||
NextSolarEclipse(date time.Time) SolarEclipseInfo
|
||||
NextSolarEclipseIAUSingleK(date time.Time) SolarEclipseInfo
|
||||
NextSolarEclipseNASABulletinSplitK(date time.Time) SolarEclipseInfo
|
||||
NextSolarEclipseWithOptions(date time.Time, options SolarEclipseOptions) SolarEclipseInfo
|
||||
SearchLocalCentralSolarEclipse(
|
||||
date time.Time, lon, lat, height float64,
|
||||
options SolarEclipseLocalSearchOptions,
|
||||
) (LocalSolarEclipseInfo, SolarEclipseLocalSearchStatus)
|
||||
SolarEclipseBesselianElements(
|
||||
seedJDE float64, options SolarEclipseBesselianElementsOptions,
|
||||
) (SolarEclipseBesselianElementsResult, bool)
|
||||
SolarEclipseBesselianMuForPublishedTable(
|
||||
mu SolarEclipseBesselianPolynomial, deltaTSeconds float64,
|
||||
) SolarEclipseBesselianPolynomial
|
||||
SolarEclipseCandidates(
|
||||
start, end time.Time, options SolarEclipseCandidateOptions,
|
||||
) []SolarEclipseCandidate
|
||||
SolarEclipseCentralPath(date time.Time, options SolarEclipsePathOptions) (SolarEclipsePath, bool)
|
||||
SolarEclipseCentralPathIAUSingleK(date time.Time, options SolarEclipsePathOptions) (SolarEclipsePath, bool)
|
||||
SolarEclipseCentralPathNASABulletinSplitK(date time.Time, options SolarEclipsePathOptions) (SolarEclipsePath, bool)
|
||||
SolarEclipseGeocentricPanelAt(date time.Time) (SolarEclipseGeocentricPanel, bool)
|
||||
SolarEclipseGeocentricPanelIAUSingleK(date time.Time) (SolarEclipseGeocentricPanel, bool)
|
||||
SolarEclipseGeocentricPanelInUT1(panel SolarEclipseGeocentricPanel) SolarEclipseGeocentricPanel
|
||||
SolarEclipseGeocentricPanelWithOptions(date time.Time, options SolarEclipseOptions) (SolarEclipseGeocentricPanel, bool)
|
||||
SolarEclipseInfoInUT1(info SolarEclipseInfo) SolarEclipseInfo
|
||||
SolarEclipseOnDate(date time.Time) (SolarEclipseInfo, bool)
|
||||
SolarEclipseOnDateIAUSingleK(date time.Time) (SolarEclipseInfo, bool)
|
||||
SolarEclipseOnDateNASABulletinSplitK(date time.Time) (SolarEclipseInfo, bool)
|
||||
SolarEclipseOnDateWithOptions(date time.Time, options SolarEclipseOptions) (SolarEclipseInfo, bool)
|
||||
SolarEclipsePartialArea(date time.Time, options SolarEclipsePartialAreaOptions) (SolarEclipsePartialAreaInfo, bool)
|
||||
SolarEclipsePartialAreaIAUSingleK(date time.Time, options SolarEclipsePartialAreaOptions) (SolarEclipsePartialAreaInfo, bool)
|
||||
SolarEclipsePartialAreaNASABulletinSplitK(date time.Time, options SolarEclipsePartialAreaOptions) (SolarEclipsePartialAreaInfo, bool)
|
||||
SolarEclipsePartialFootprints(date time.Time, options SolarEclipsePartialFootprintOptions) (SolarEclipsePartialFootprintsInfo, bool)
|
||||
SolarEclipsePartialFootprintsIAUSingleK(date time.Time, options SolarEclipsePartialFootprintOptions) (SolarEclipsePartialFootprintsInfo, bool)
|
||||
SolarEclipsePartialFootprintsInUT1(info SolarEclipsePartialFootprintsInfo) SolarEclipsePartialFootprintsInfo
|
||||
SolarEclipsePartialFootprintsNASABulletinSplitK(date time.Time, options SolarEclipsePartialFootprintOptions) (SolarEclipsePartialFootprintsInfo, bool)
|
||||
SolarEclipsePathInUT1(path SolarEclipsePath) SolarEclipsePath
|
||||
SolarEclipseShadowAt(value time.Time) (SolarEclipseShadowInstant, bool)
|
||||
SolarEclipseShadowBetween(
|
||||
start, end time.Time, step time.Duration,
|
||||
) []SolarEclipseShadowInstant
|
||||
SolarEclipseShadowBetweenWithOptions(
|
||||
start, end time.Time, step time.Duration, options SolarEclipseShadowSolverOptions,
|
||||
) []SolarEclipseShadowInstant
|
||||
SolarEclipseStationStateAt(value time.Time, lon, lat, height float64) SolarEclipseStationState
|
||||
TimeLabelsInUT1(times []time.Time) []time.Time
|
||||
}
|
||||
|
||||
var _ contextAPI = (*Eclipse)(nil)
|
||||
|
||||
func TestContextModuleIsolation(t *testing.T) {
|
||||
previous := basic.GetEphemerisModel()
|
||||
t.Cleanup(func() { basic.SetEphemerisModel(previous) })
|
||||
date := time.Date(2024, 4, 8, 0, 0, 0, 0, time.UTC)
|
||||
for _, model := range []ephem.Model{ephem.Legacy, ephem.Semianalytic} {
|
||||
basic.SetEphemerisModel(basic.EphemerisModel(model))
|
||||
want, wantOK := SolarEclipseOnDate(date)
|
||||
module := NewWithInstance(ephem.NewModelInstance(model))
|
||||
basic.SetEphemerisModel(basic.EphemerisModel(1 - int(model)))
|
||||
got, gotOK := module.SolarEclipseOnDate(date)
|
||||
if !wantOK || gotOK != wantOK || got != want {
|
||||
t.Fatalf("model %d: solar eclipse escaped instance", model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 站心日食、候选枚举与中心食搜索必须使用模块实例,切换全局模型不得改变结果。
|
||||
func TestContextLocalSolarEclipseIsolation(t *testing.T) {
|
||||
previous := basic.GetEphemerisModel()
|
||||
t.Cleanup(func() { basic.SetEphemerisModel(previous) })
|
||||
date := time.Date(2024, 3, 1, 0, 0, 0, 0, time.UTC)
|
||||
for _, model := range []ephem.Model{ephem.Legacy, ephem.Semianalytic} {
|
||||
module := NewWithInstance(ephem.NewModelInstance(model))
|
||||
run := func() []interface{} {
|
||||
next := module.NextLocalSolarEclipse(date, -97, 32, 0)
|
||||
iau := module.NextLocalSolarEclipseIAUSingleK(date, -97, 32, 0)
|
||||
onDate, ok := module.LocalSolarEclipseOnDate(time.Date(2024, 4, 8, 0, 0, 0, 0, time.UTC), -97, 32, 0)
|
||||
candidates := module.SolarEclipseCandidates(date, date.AddDate(1, 0, 0), SolarEclipseCandidateOptions{})
|
||||
central, status := module.SearchLocalCentralSolarEclipse(date, -97, 32, 0, SolarEclipseLocalSearchOptions{MaxYears: 2})
|
||||
return []interface{}{next, iau, onDate, ok, candidates, central, status}
|
||||
}
|
||||
basic.SetEphemerisModel(basic.EphemerisModel(model))
|
||||
want := run()
|
||||
basic.SetEphemerisModel(basic.EphemerisModel(1 - int(model)))
|
||||
got := run()
|
||||
for i := range want {
|
||||
if !reflect.DeepEqual(got[i], want[i]) {
|
||||
t.Fatalf("model %d: result %d escaped instance:\n got %+v\nwant %+v", model, i, got[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user