feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"b612.me/astro/planet"
|
||||
. "b612.me/astro/tools"
|
||||
)
|
||||
|
||||
const (
|
||||
// 月球和内行星轨道角速度更快,取更小的中心差分步长。
|
||||
orbitalNodeStepFastBodyDays = 0.005
|
||||
// 外行星保留更稳健的 0.01 day 步长,避免无意义地放大数值噪声。
|
||||
orbitalNodeStepSlowBodyDays = 0.01
|
||||
)
|
||||
|
||||
// MoonAscendingNode 月球升交点黄经 / ascending node longitude of the Moon.
|
||||
func MoonAscendingNode(jd float64) float64 {
|
||||
return MoonAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// MoonAscendingNodeN 月球升交点黄经(截断版) / truncated ascending node longitude of the Moon.
|
||||
func MoonAscendingNodeN(jd float64, n int) float64 {
|
||||
return orbitalAscendingNodeLongitude(jd, n, orbitalNodeStepFastBodyDays, moonGeocentricNodePositionN)
|
||||
}
|
||||
|
||||
// MoonDescendingNode 月球降交点黄经 / descending node longitude of the Moon.
|
||||
func MoonDescendingNode(jd float64) float64 {
|
||||
return MoonDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// MoonDescendingNodeN 月球降交点黄经(截断版) / truncated descending node longitude of the Moon.
|
||||
func MoonDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(MoonAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// MercuryAscendingNode 水星升交点黄经 / ascending node longitude of Mercury.
|
||||
func MercuryAscendingNode(jd float64) float64 {
|
||||
return MercuryAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// MercuryAscendingNodeN 水星升交点黄经(截断版) / truncated ascending node longitude of Mercury.
|
||||
func MercuryAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(1, jd, n)
|
||||
}
|
||||
|
||||
// MercuryDescendingNode 水星降交点黄经 / descending node longitude of Mercury.
|
||||
func MercuryDescendingNode(jd float64) float64 {
|
||||
return MercuryDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// MercuryDescendingNodeN 水星降交点黄经(截断版) / truncated descending node longitude of Mercury.
|
||||
func MercuryDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(MercuryAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// VenusAscendingNode 金星升交点黄经 / ascending node longitude of Venus.
|
||||
func VenusAscendingNode(jd float64) float64 {
|
||||
return VenusAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// VenusAscendingNodeN 金星升交点黄经(截断版) / truncated ascending node longitude of Venus.
|
||||
func VenusAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(2, jd, n)
|
||||
}
|
||||
|
||||
// VenusDescendingNode 金星降交点黄经 / descending node longitude of Venus.
|
||||
func VenusDescendingNode(jd float64) float64 {
|
||||
return VenusDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// VenusDescendingNodeN 金星降交点黄经(截断版) / truncated descending node longitude of Venus.
|
||||
func VenusDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(VenusAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// MarsAscendingNode 火星升交点黄经 / ascending node longitude of Mars.
|
||||
func MarsAscendingNode(jd float64) float64 {
|
||||
return MarsAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// MarsAscendingNodeN 火星升交点黄经(截断版) / truncated ascending node longitude of Mars.
|
||||
func MarsAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(3, jd, n)
|
||||
}
|
||||
|
||||
// MarsDescendingNode 火星降交点黄经 / descending node longitude of Mars.
|
||||
func MarsDescendingNode(jd float64) float64 {
|
||||
return MarsDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// MarsDescendingNodeN 火星降交点黄经(截断版) / truncated descending node longitude of Mars.
|
||||
func MarsDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(MarsAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// JupiterAscendingNode 木星升交点黄经 / ascending node longitude of Jupiter.
|
||||
func JupiterAscendingNode(jd float64) float64 {
|
||||
return JupiterAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// JupiterAscendingNodeN 木星升交点黄经(截断版) / truncated ascending node longitude of Jupiter.
|
||||
func JupiterAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(4, jd, n)
|
||||
}
|
||||
|
||||
// JupiterDescendingNode 木星降交点黄经 / descending node longitude of Jupiter.
|
||||
func JupiterDescendingNode(jd float64) float64 {
|
||||
return JupiterDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// JupiterDescendingNodeN 木星降交点黄经(截断版) / truncated descending node longitude of Jupiter.
|
||||
func JupiterDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(JupiterAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// SaturnAscendingNode 土星升交点黄经 / ascending node longitude of Saturn.
|
||||
func SaturnAscendingNode(jd float64) float64 {
|
||||
return SaturnAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// SaturnAscendingNodeN 土星升交点黄经(截断版) / truncated ascending node longitude of Saturn.
|
||||
func SaturnAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(5, jd, n)
|
||||
}
|
||||
|
||||
// SaturnDescendingNode 土星降交点黄经 / descending node longitude of Saturn.
|
||||
func SaturnDescendingNode(jd float64) float64 {
|
||||
return SaturnDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// SaturnDescendingNodeN 土星降交点黄经(截断版) / truncated descending node longitude of Saturn.
|
||||
func SaturnDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(SaturnAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// UranusAscendingNode 天王星升交点黄经 / ascending node longitude of Uranus.
|
||||
func UranusAscendingNode(jd float64) float64 {
|
||||
return UranusAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// UranusAscendingNodeN 天王星升交点黄经(截断版) / truncated ascending node longitude of Uranus.
|
||||
func UranusAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(6, jd, n)
|
||||
}
|
||||
|
||||
// UranusDescendingNode 天王星降交点黄经 / descending node longitude of Uranus.
|
||||
func UranusDescendingNode(jd float64) float64 {
|
||||
return UranusDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// UranusDescendingNodeN 天王星降交点黄经(截断版) / truncated descending node longitude of Uranus.
|
||||
func UranusDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(UranusAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
// NeptuneAscendingNode 海王星升交点黄经 / ascending node longitude of Neptune.
|
||||
func NeptuneAscendingNode(jd float64) float64 {
|
||||
return NeptuneAscendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// NeptuneAscendingNodeN 海王星升交点黄经(截断版) / truncated ascending node longitude of Neptune.
|
||||
func NeptuneAscendingNodeN(jd float64, n int) float64 {
|
||||
return planetAscendingNodeLongitudeN(7, jd, n)
|
||||
}
|
||||
|
||||
// NeptuneDescendingNode 海王星降交点黄经 / descending node longitude of Neptune.
|
||||
func NeptuneDescendingNode(jd float64) float64 {
|
||||
return NeptuneDescendingNodeN(jd, -1)
|
||||
}
|
||||
|
||||
// NeptuneDescendingNodeN 海王星降交点黄经(截断版) / truncated descending node longitude of Neptune.
|
||||
func NeptuneDescendingNodeN(jd float64, n int) float64 {
|
||||
return Limit360(NeptuneAscendingNodeN(jd, n) + 180)
|
||||
}
|
||||
|
||||
func planetAscendingNodeLongitudeN(planetIndex int, jd float64, n int) float64 {
|
||||
step := orbitalNodeStepSlowBodyDays
|
||||
if planetIndex <= 3 {
|
||||
step = orbitalNodeStepFastBodyDays
|
||||
}
|
||||
return orbitalAscendingNodeLongitude(jd, n, step, func(sampleJD float64, seriesTerms int) Vector3 {
|
||||
return planetHeliocentricNodePositionN(planetIndex, sampleJD, seriesTerms)
|
||||
})
|
||||
}
|
||||
|
||||
func orbitalAscendingNodeLongitude(jd float64, n int, step float64, position func(float64, int) Vector3) float64 {
|
||||
current := eclipticVectorAtReferenceEpoch(position(jd, n), jd, jd)
|
||||
previous := eclipticVectorAtReferenceEpoch(position(jd-step, n), jd-step, jd)
|
||||
next := eclipticVectorAtReferenceEpoch(position(jd+step, n), jd+step, jd)
|
||||
|
||||
velocity := Vector3{
|
||||
(next[0] - previous[0]) / (2 * step),
|
||||
(next[1] - previous[1]) / (2 * step),
|
||||
(next[2] - previous[2]) / (2 * step),
|
||||
}
|
||||
angularMomentum := pxp(current, velocity)
|
||||
nodeVector, magnitude := pn(Vector3{-angularMomentum[1], angularMomentum[0], 0})
|
||||
if magnitude == 0 {
|
||||
return 0
|
||||
}
|
||||
return Limit360(math.Atan2(nodeVector[1], nodeVector[0]) * deg)
|
||||
}
|
||||
|
||||
func eclipticVectorAtReferenceEpoch(vector Vector3, sampleJD, referenceJD float64) Vector3 {
|
||||
if sampleJD == referenceJD {
|
||||
return vector
|
||||
}
|
||||
|
||||
sampleEquatorial := rotateEclipticToEquatorial(vector, EclipticObliquity(sampleJD, false))
|
||||
precessedEquatorial := applyMatrix3(precessionMatrix(sampleJD, referenceJD), sampleEquatorial)
|
||||
return rotateEquatorialToEcliptic(precessedEquatorial, EclipticObliquity(referenceJD, false))
|
||||
}
|
||||
|
||||
func rotateEclipticToEquatorial(vector Vector3, obliquity float64) Vector3 {
|
||||
epsilon := obliquity * rad
|
||||
cosEpsilon := math.Cos(epsilon)
|
||||
sinEpsilon := math.Sin(epsilon)
|
||||
return Vector3{
|
||||
vector[0],
|
||||
vector[1]*cosEpsilon - vector[2]*sinEpsilon,
|
||||
vector[1]*sinEpsilon + vector[2]*cosEpsilon,
|
||||
}
|
||||
}
|
||||
|
||||
func rotateEquatorialToEcliptic(vector Vector3, obliquity float64) Vector3 {
|
||||
epsilon := obliquity * rad
|
||||
cosEpsilon := math.Cos(epsilon)
|
||||
sinEpsilon := math.Sin(epsilon)
|
||||
return Vector3{
|
||||
vector[0],
|
||||
vector[1]*cosEpsilon + vector[2]*sinEpsilon,
|
||||
-vector[1]*sinEpsilon + vector[2]*cosEpsilon,
|
||||
}
|
||||
}
|
||||
|
||||
func precessionMatrix(jdFrom, jdTo float64) Matrix3 {
|
||||
epjFrom := 2000.0 + (jdFrom-2451545.0)/365.25
|
||||
epjTo := 2000.0 + (jdTo-2451545.0)/365.25
|
||||
|
||||
rpFrom := ltpPMAT(epjFrom)
|
||||
rpFromInv := Matrix3{
|
||||
{rpFrom[0][0], rpFrom[1][0], rpFrom[2][0]},
|
||||
{rpFrom[0][1], rpFrom[1][1], rpFrom[2][1]},
|
||||
{rpFrom[0][2], rpFrom[1][2], rpFrom[2][2]},
|
||||
}
|
||||
rpTo := ltpPMAT(epjTo)
|
||||
|
||||
var result Matrix3
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
for k := 0; k < 3; k++ {
|
||||
result[i][j] += rpTo[i][k] * rpFromInv[k][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func applyMatrix3(matrix Matrix3, vector Vector3) Vector3 {
|
||||
return Vector3{
|
||||
matrix[0][0]*vector[0] + matrix[0][1]*vector[1] + matrix[0][2]*vector[2],
|
||||
matrix[1][0]*vector[0] + matrix[1][1]*vector[1] + matrix[1][2]*vector[2],
|
||||
matrix[2][0]*vector[0] + matrix[2][1]*vector[1] + matrix[2][2]*vector[2],
|
||||
}
|
||||
}
|
||||
|
||||
func planetHeliocentricNodePositionN(planetIndex int, jd float64, n int) Vector3 {
|
||||
longitude := planet.WherePlanetN(planetIndex, 0, jd, n)
|
||||
latitude := planet.WherePlanetN(planetIndex, 1, jd, n)
|
||||
radius := planet.WherePlanetN(planetIndex, 2, jd, n)
|
||||
return eclipticCartesian(longitude, latitude, radius)
|
||||
}
|
||||
|
||||
func moonGeocentricNodePositionN(jd float64, n int) Vector3 {
|
||||
longitude := HMoonTrueLoN(jd, n)
|
||||
latitude := HMoonTrueBoN(jd, n)
|
||||
radius := HMoonAwayN(jd, n)
|
||||
return eclipticCartesian(longitude, latitude, radius)
|
||||
}
|
||||
|
||||
func eclipticCartesian(longitude, latitude, radius float64) Vector3 {
|
||||
cosLatitude := Cos(latitude)
|
||||
return Vector3{
|
||||
radius * cosLatitude * Cos(longitude),
|
||||
radius * cosLatitude * Sin(longitude),
|
||||
radius * Sin(latitude),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user