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), } }