feat: 引入可切换星历模型并扩展天象观测链路

- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算
- 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询
- 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出
- 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解
- 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤
- 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持
- 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理
- 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
This commit is contained in:
2026-10-15 23:54:15 +08:00
parent 16c62a97d5
commit 044f2f4381
674 changed files with 62983 additions and 8396 deletions
+25 -5
View File
@@ -4,6 +4,8 @@ import (
"math"
"sort"
"time"
"b612.me/astro/internal/geodata"
)
func appendOccultationRiseSetSamples(
@@ -485,7 +487,7 @@ func occultationRiseSetRecoverNarrowPhaseJunction(
if !middleOK || !occultationRiseSetDirectionMatches(evaluation, middle, direction) {
outside = OccultationPathPoint{
Time: occultationTTToLocation(middleTT, location),
Longitude: normalizeLongitude(
Longitude: geodata.NormalizeLongitude(
inside.Longitude + math.Remainder(outside.Longitude-inside.Longitude, 360)/2,
),
Latitude: (inside.Latitude + outside.Latitude) / 2,
@@ -506,6 +508,24 @@ func occultationRiseSetRecoverNarrowPhaseJunction(
if math.Abs(outsideContact) < math.Abs(insideContact) {
secondary = outside
}
// 时间区间收缩后两地平根仍差求根精度,沿短弦插值接触零点而不是取较优端点。
if denominator := insideContact - outsideContact; denominator != 0 {
weight := insideContact / denominator
insideTT := occultationTimeToTT(inside.Time)
interpolatedTT := insideTT + (occultationTimeToTT(outside.Time)-insideTT)*weight
interpolated := OccultationPathPoint{
Time: occultationTTToLocation(interpolatedTT, location),
Longitude: geodata.NormalizeLongitude(
inside.Longitude + math.Remainder(outside.Longitude-inside.Longitude, 360)*weight,
),
Latitude: inside.Latitude + (outside.Latitude-inside.Latitude)*weight,
}
state := cache.evaluation(interpolatedTT).center.stateAt(interpolated.Longitude, interpolated.Latitude)
if state.valid && finite(state.contactMetric) &&
math.Abs(state.contactMetric) < math.Min(math.Abs(insideContact), math.Abs(outsideContact)) {
secondary = interpolated
}
}
secondaryTT := occultationTimeToTT(secondary.Time)
secondaryEvaluation := cache.evaluation(secondaryTT)
secondaryState := secondaryEvaluation.center.stateAt(secondary.Longitude, secondary.Latitude)
@@ -624,7 +644,7 @@ func occultationRiseSetMidpoint(first, second OccultationPathPoint) OccultationP
secondTT := occultationTimeToTT(second.Time)
return OccultationPathPoint{
Time: occultationTTToLocation((firstTT+secondTT)/2, first.Time.Location()),
Longitude: normalizeLongitude(
Longitude: geodata.NormalizeLongitude(
first.Longitude + math.Remainder(second.Longitude-first.Longitude, 360)/2,
),
Latitude: (first.Latitude + second.Latitude) / 2,
@@ -672,7 +692,7 @@ func completeOccultationRiseSetDirectionJunctions(
riseEndpoint.point, setEndpoint.point, phase == RiseSetPhaseGreatest, location, cache,
)
if !ok {
longitude := normalizeLongitude(riseEndpoint.point.Longitude + math.Remainder(setEndpoint.point.Longitude-riseEndpoint.point.Longitude, 360)/2)
longitude := geodata.NormalizeLongitude(riseEndpoint.point.Longitude + math.Remainder(setEndpoint.point.Longitude-riseEndpoint.point.Longitude, 360)/2)
latitude := (riseEndpoint.point.Latitude + setEndpoint.point.Latitude) / 2
junction, ok = refineOccultationRiseSetDirectionJunction(
(occultationTimeToTT(riseEndpoint.point.Time)+occultationTimeToTT(setEndpoint.point.Time))/2,
@@ -919,7 +939,7 @@ func refineOccultationRiseSetPhaseJunction(
return OccultationPathPoint{}, false
}
occultationRiseSetLimitJunctionDelta(&delta)
coordinates[0] = normalizeLongitude(coordinates[0] + delta[0])
coordinates[0] = geodata.NormalizeLongitude(coordinates[0] + delta[0])
coordinates[1] += delta[1]
coordinates[2] += delta[2]
if coordinates[1] <= -89.999999 || coordinates[1] >= 89.999999 {
@@ -1031,7 +1051,7 @@ func refineOccultationRiseSetDirectionJunction(
return OccultationPathPoint{}, false
}
occultationRiseSetLimitJunctionDelta(&delta)
coordinates[0] = normalizeLongitude(coordinates[0] + delta[0])
coordinates[0] = geodata.NormalizeLongitude(coordinates[0] + delta[0])
coordinates[1] += delta[1]
coordinates[2] += delta[2]
if coordinates[1] <= -89.999999 || coordinates[1] >= 89.999999 {