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
+90
View File
@@ -0,0 +1,90 @@
package basic
import (
"math"
"b612.me/astro/internal/ephem"
. "b612.me/astro/tools"
)
// topocentricHourAngleDec 由地心视赤经、视赤纬(度)与地心距(AU)给出观测者处的站心时角与站心视赤纬(度)。
// 恒星时只算一次,视差修正与时角共用;观测者取海拔 0,海拔对太阳系天体视差的影响可忽略。
func topocentricHourAngleDec(utcJD, lon, lat, ra, dec, distanceAU float64) (hourAngle, topocentricDec float64) {
gast := ApparentSiderealTime(UTC2UT1(utcJD)) * 15
topocentricRA, topocentricDec := topocentricRaDecWithSidereal(ra, dec, lat, lon, gast, distanceAU, 0)
return Limit360(gast + lon - topocentricRA), topocentricDec
}
// horizontalAltitude 时角、赤纬、纬度(度)转高度角 / altitude from hour angle, declination and latitude.
func horizontalAltitude(hourAngle, dec, lat float64) float64 {
return ArcSin(Sin(lat)*Sin(dec) + Cos(dec)*Cos(lat)*Cos(hourAngle))
}
// horizontalAzimuth 时角、赤纬、纬度(度)转方位角,北起向东 / azimuth from north through east.
func horizontalAzimuth(hourAngle, dec, lat float64) float64 {
tanAzimuth := Sin(hourAngle) / (Cos(hourAngle)*Sin(lat) - Tan(dec)*Cos(lat))
azimuth := ArcTan(tanAzimuth)
if azimuth < 0 {
if hourAngle/15 < 12 {
return azimuth + 360
}
return azimuth + 180
}
if hourAngle/15 < 12 {
return azimuth + 180
}
return azimuth
}
// planetApparentRaDecDistanceNWithInstance 行星地心视赤经、视赤纬与几何地心距,三者取自同一次求值。
func planetApparentRaDecDistanceNWithInstance(index int, jde float64, n int, inst *Instance) (ra, dec, distanceAU float64) {
geo, _, distanceAU, ok := planetApparentPositionWithInstance(index, jde, n, inst)
if !ok || math.IsNaN(geo.lo) || math.IsNaN(geo.bo) {
return math.NaN(), math.NaN(), math.NaN()
}
ra, dec = planetApparentRaDecFromLoBo(jde, geo.lo, geo.bo)
return ra, dec, distanceAU
}
func planetTopocentricHourAngleDecN(index int, localJD, lon, lat, timezone float64, n int, inst *Instance) (float64, float64) {
utcJD := localJD - timezone/24.0
ra, dec, distanceAU := planetApparentRaDecDistanceNWithInstance(index, UTC2TT(utcJD), n, inst)
return topocentricHourAngleDec(utcJD, lon, lat, ra, dec, distanceAU)
}
// planetHeightN 行星站心视高度角(度,不含折射)/ topocentric planet altitude without refraction.
func planetHeightN(index int, localJD, lon, lat, timezone float64, n int, inst *Instance) float64 {
hourAngle, dec := planetTopocentricHourAngleDecN(index, localJD, lon, lat, timezone, n, inst)
return horizontalAltitude(hourAngle, dec, lat)
}
// planetAzimuthN 行星站心方位角(度)/ topocentric planet azimuth.
func planetAzimuthN(index int, localJD, lon, lat, timezone float64, n int, inst *Instance) float64 {
hourAngle, dec := planetTopocentricHourAngleDecN(index, localJD, lon, lat, timezone, n, inst)
return horizontalAzimuth(hourAngle, dec, lat)
}
// sunTopocentricHourAngleDecN 太阳站心时角、站心视赤纬与地日距 / topocentric solar hour angle, declination and distance.
func sunTopocentricHourAngleDecN(jd, lon, lat, tz float64, n int, inst *Instance) (hourAngle, dec, distanceAU float64) {
utcJD := jd - tz/24.0
ra, dec, distanceAU := hSunApparentRaDecDistanceN(UTC2TT(utcJD), n, inst)
hourAngle, dec = topocentricHourAngleDec(utcJD, lon, lat, ra, dec, distanceAU)
return hourAngle, dec, distanceAU
}
// sunAzimuthN 地距只用于视差,矢量视位置可用时直接取其距离,省去一次地距求值。
func sunAzimuthN(jd, lon, lat, tz float64, n int, inst *Instance) float64 {
utcJD := jd - tz/24.0
tt := UTC2TT(utcJD)
var ra, dec, distanceAU float64
if lo, bo, _, dist, ok, err := vectorApparentWithInstance(ephem.Sun, tt, n, inst); err != nil {
return math.NaN()
} else if ok {
ra, dec = LoBoToRaDec(tt, lo, bo)
distanceAU = dist
} else {
ra, dec, distanceAU = hSunApparentRaDecDistanceN(tt, n, inst)
}
hourAngle, topocentricDec := topocentricHourAngleDec(utcJD, lon, lat, ra, dec, distanceAU)
return horizontalAzimuth(hourAngle, topocentricDec, lat)
}