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
+7 -15
View File
@@ -21,7 +21,7 @@ import (
"math"
"time"
"b612.me/astro"
"b612.me/astro/basic"
"b612.me/astro/internal/geodata"
)
@@ -75,7 +75,7 @@ type TimeMarkerOptions struct {
// 并在集合上输出 time_scale 成员消歧(RFC 3339 的 Z 后缀严格说不等于 UT1)。此时 Location 必须是 nil 或 UTC。
// TimeScale selects the scale of time properties: the zero value is UTC; TimeScaleUT1 writes UT1 labels
// and adds a time_scale member (a RFC 3339 Z suffix is not exactly UT1). Location must then be nil or UTC.
TimeScale astro.TimeScale
TimeScale basic.TimeScale
}
// dropFeaturesByRole 按 role 属性丢弃要素;空列表原样返回。
@@ -108,7 +108,7 @@ func marshalEmptyFeatureCollection() ([]byte, error) {
return encodeFeatureCollection(make([]feature, 0))
}
func marshalFeatureCollectionWithTimeScale(features []feature, scale astro.TimeScale) ([]byte, error) {
func marshalFeatureCollectionWithTimeScale(features []feature, scale basic.TimeScale) ([]byte, error) {
if len(features) == 0 {
return nil, fmt.Errorf("geojson: no geographic features")
}
@@ -116,12 +116,12 @@ func marshalFeatureCollectionWithTimeScale(features []feature, scale astro.TimeS
}
func encodeFeatureCollection(features []feature) ([]byte, error) {
return encodeFeatureCollectionWithTimeScale(features, astro.TimeScaleUTC)
return encodeFeatureCollectionWithTimeScale(features, basic.TimeScaleUTC)
}
func encodeFeatureCollectionWithTimeScale(features []feature, scale astro.TimeScale) ([]byte, error) {
func encodeFeatureCollectionWithTimeScale(features []feature, scale basic.TimeScale) ([]byte, error) {
member := ""
if scale == astro.TimeScaleUT1 {
if scale == basic.TimeScaleUT1 {
member = "UT1"
}
value, err := json.Marshal(featureCollection{Type: featureCollectionType, Features: features, TimeScale: member})
@@ -304,7 +304,7 @@ func interpolateTimeMarker(a, b pathSample, fraction float64, value time.Time) p
}
return pathSample{
Time: value,
Longitude: normalizeLongitude(a.Longitude + fraction*deltaLongitude),
Longitude: geodata.NormalizeLongitude(a.Longitude + fraction*deltaLongitude),
Latitude: a.Latitude + fraction*(b.Latitude-a.Latitude),
}
}
@@ -613,11 +613,3 @@ func formatTime(value time.Time) string {
}
return value.UTC().Format(time.RFC3339Nano)
}
func normalizeLongitude(value float64) float64 {
value = math.Mod(value+180, 360)
if value < 0 {
value += 360
}
return value - 180
}