2019-10-24 10:44:21 +08:00
package planet
import (
. "b612.me/astro/tools"
2022-05-16 20:42:15 +08:00
"math"
2019-10-24 10:44:21 +08:00
)
2022-05-16 20:42:15 +08:00
2026-09-23 18:55:12 +08:00
// WherePlanet 天体 xt 在儒略日 jde 的 VSOP 结果 / VSOP result for body xt at Julian day jde.
2026-09-17 12:27:40 +08:00
//
// xt 取 -1 或 0..7:0 为地球,1..7 依次为水星、金星、火星、木星、土星、天王星、海王星;-1 表示地球,zn 取 0 时给日心黄经。
// zn 取 0 黄经、1 黄纬、2 日心距(AU);xt 或 zn 越界返回 NaN 而不 panic。
// xt is -1 or 0..7 (0 Earth, 1..7 Mercury through Neptune; -1 selects Earth, giving its heliocentric longitude for zn 0).
// zn is 0 longitude, 1 latitude, 2 heliocentric distance in AU; an out-of-range xt or zn yields NaN instead of panicking.
2026-09-23 18:55:12 +08:00
func WherePlanet ( xt , zn int , jde float64 ) float64 {
return WherePlanetN ( xt , zn , jde , - 1 )
2026-05-01 22:38:44 +08:00
}
2022-05-16 20:42:15 +08:00
2026-09-17 12:27:40 +08:00
// WherePlanetN 同 WherePlanet 的截断版 / truncated form of WherePlanet.
//
// n < 0 时使用全部项;否则保留约 n 个主项并按比例缩短高阶项。取值域与越界行为同 WherePlanet。
// When n < 0 all terms are used; otherwise roughly n principal terms are kept and higher orders scaled proportionally. Domain and out-of-range behavior match WherePlanet.
2026-09-23 18:55:12 +08:00
func WherePlanetN ( xt , zn int , jde float64 , n int ) float64 {
2026-09-17 12:27:40 +08:00
if xt < - 1 || xt > 7 || zn < 0 || zn > 2 {
return math . NaN ()
}
2022-05-16 20:42:15 +08:00
sata := 0
if xt == - 1 {
xt = 0
sata = 1
}
2019-10-24 10:44:21 +08:00
2026-05-01 22:38:44 +08:00
rad := 180.0000 * 3600.0000 / math . Pi
2026-09-23 18:55:12 +08:00
t := ( jde - 2451545 ) / 36525.0000
2026-05-01 22:38:44 +08:00
t /= 10 // 转为儒略千年数
2026-05-17 21:19:23 +08:00
body := planetViews ()[ xt ]
2026-05-01 22:38:44 +08:00
coord := body . coords [ zn ]
baseOrderTerms := len ( coord . orders [ 0 ])
2019-10-24 10:44:21 +08:00
2022-05-16 20:42:15 +08:00
tn := float64 ( 1 )
2026-05-01 22:38:44 +08:00
var v float64
for i , series := range coord . orders {
seriesLength := len ( series )
if seriesLength == 0 {
2022-05-16 20:42:15 +08:00
continue
}
2026-05-01 22:38:44 +08:00
termLimit := seriesLength
if n >= 0 {
termLimit = int ( math . Floor ( 3 * float64 ( n ) * float64 ( seriesLength ) / float64 ( baseOrderTerms ) + 0.5 ))
if i != 0 {
termLimit += 3
}
if termLimit > seriesLength {
termLimit = seriesLength
}
2019-10-24 10:44:21 +08:00
}
2022-05-16 20:42:15 +08:00
var c float64
2026-05-01 22:38:44 +08:00
for j := 0 ; j < termLimit ; j += 3 {
c += series [ j ] * math . Cos ( series [ j + 1 ] + t * series [ j + 2 ])
2019-10-24 10:44:21 +08:00
}
2022-05-16 20:42:15 +08:00
v += c * tn
tn *= t
2019-10-24 10:44:21 +08:00
}
2026-05-01 22:38:44 +08:00
v /= body . scale
2022-05-16 20:42:15 +08:00
2026-05-01 22:38:44 +08:00
if xt == 0 { // 地球
2022-05-16 20:42:15 +08:00
t2 := t * t
2026-05-01 22:38:44 +08:00
t3 := t2 * t // 千年数的各次方
2022-05-16 20:42:15 +08:00
if zn == 0 {
v += ( - 0.0728 - 2.7702 * t - 1.1019 * t2 - 0.0996 * t3 ) / rad
} else if zn == 1 {
v += ( + 0.0000 + 0.0004 * t + 0.0004 * t2 - 0.0026 * t3 ) / rad
} else if zn == 2 {
v += ( - 0.0020 + 0.0044 * t + 0.0213 * t2 - 0.0250 * t3 ) / 1000000
2019-10-24 10:44:21 +08:00
}
2026-05-01 22:38:44 +08:00
} else { // 其它行星
planetCorrections := [] float64 {
// 经(角秒), 纬(角秒), 距(10-6AU)
- 0.08631 , + 0.00039 , - 0.00008 , // 水星
- 0.07447 , + 0.00006 , + 0.00017 , // 金星
- 0.07135 , - 0.00026 , - 0.00176 , // 火星
- 0.20239 , + 0.00273 , - 0.00347 , // 木星
- 0.25486 , + 0.00276 , + 0.42926 , // 土星
+ 0.24588 , + 0.00345 , - 14.46266 , // 天王星
- 0.95116 , + 0.02481 , + 58.30651 , // 海王星
2019-10-24 10:44:21 +08:00
}
2026-05-01 22:38:44 +08:00
dv := planetCorrections [( xt - 1 ) * 3 + zn ]
2022-05-16 20:42:15 +08:00
if zn == 0 {
v += - 3 * t / rad
2019-10-24 10:44:21 +08:00
}
2022-05-16 20:42:15 +08:00
if zn == 2 {
v += dv / 1000000
} else {
v += dv / rad
}
}
2026-05-01 22:38:44 +08:00
2022-05-16 20:42:15 +08:00
if zn == 0 && xt == 0 {
if sata != 0 {
2026-05-01 22:38:44 +08:00
return Limit360 ( v * 180 / math . Pi )
2022-05-16 20:42:15 +08:00
}
2026-05-01 22:38:44 +08:00
return Limit360 ( v * 180 / math . Pi + 180 )
2022-05-16 20:42:15 +08:00
}
if zn == 1 && xt == 0 {
if sata != 0 {
2026-05-01 22:38:44 +08:00
return v * 180 / math . Pi
2022-05-16 20:42:15 +08:00
}
2026-05-01 22:38:44 +08:00
return - ( v * 180 / math . Pi )
2022-05-16 20:42:15 +08:00
}
if xt > 0 && zn == 1 {
2026-05-01 22:38:44 +08:00
return v * 180 / math . Pi
2022-05-16 20:42:15 +08:00
}
if xt > 0 && zn == 0 {
2026-05-01 22:38:44 +08:00
return Limit360 ( v * 180 / math . Pi )
2022-05-16 20:42:15 +08:00
}
return v
}