1 | import circle from '@robireton/circle'
|
2 | import JulianEphemerisDay from './julian-day'
|
3 | import calculateNutationAndObliquity from './nutation-obliquity'
|
4 | import earthVSOP87D from './vsop87d-earth'
|
5 |
|
6 | export function positionSun (date, lat, lon) {
|
7 | const JDE = JulianEphemerisDay(date)
|
8 | const heliocentric = positionEarth(JDE)
|
9 |
|
10 |
|
11 | let Θ = circle.normalizedDegrees(heliocentric.L + 180)
|
12 | let β = -heliocentric.B
|
13 |
|
14 |
|
15 | const T = (JDE - 2451545) / 36525
|
16 | const λ_ = Θ + T * (-1.397 + T * (-0.00031 * T))
|
17 | const ΔΘ = -0.09033 / 3600
|
18 | const Δβ = (0.03916 / 3600) * (Math.cos(circle.DegreesToRadians(λ_)) - Math.sin(circle.DegreesToRadians(λ_)))
|
19 | Θ += ΔΘ
|
20 | β += Δβ
|
21 |
|
22 |
|
23 | const objNutObl = calculateNutationAndObliquity(JDE)
|
24 | const λ = Θ + objNutObl.Δψ - (20.4898 / 3600) / heliocentric.R
|
25 |
|
26 |
|
27 | const ε = circle.DegreesToRadians(objNutObl.ε)
|
28 | const α = circle.normalizedDegrees(circle.RadiansToDegrees(Math.atan2(Math.sin(circle.DegreesToRadians(λ)) * Math.cos(ε) - Math.tan(circle.DegreesToRadians(β)) * Math.sin(ε), Math.cos(circle.DegreesToRadians(λ)))))
|
29 | const δ = circle.RadiansToDegrees(Math.asin(Math.sin(circle.DegreesToRadians(β)) * Math.cos(ε) + Math.cos(circle.DegreesToRadians(β)) * Math.sin(ε) * Math.sin(circle.DegreesToRadians(λ))))
|
30 |
|
31 |
|
32 | const τ = T / 10
|
33 | const L0 = circle.normalizedDegrees(280.4664567 + τ * (360007.6982779 + τ * (0.03032028 + τ * (1 / 49931 + τ * (-1 / 15299 - τ / 1988000)))))
|
34 | let E = circle.normalizedDegrees(L0 - 0.0057183 - α + objNutObl.Δψ * Math.cos(ε))
|
35 | if (E > 180) E -= 360
|
36 | E *= 4
|
37 |
|
38 | let A, h
|
39 | if (!isNaN(lat) && !isNaN(lon)) {
|
40 | const θ0 = circle.normalizedDegrees(280.46061837 + 360.98564736629 * (JDE - 2451545.0) + 0.000387933 * T * T + T * T * T / 38710000) + objNutObl.Δψ * Math.cos(ε)
|
41 |
|
42 | const L = -lon
|
43 | const φ = lat
|
44 |
|
45 | const H = circle.normalizedDegrees(θ0 - L - α)
|
46 |
|
47 | A = circle.normalizedDegrees(180 + circle.RadiansToDegrees(Math.atan2(Math.sin(circle.DegreesToRadians(H)), Math.cos(circle.DegreesToRadians(H)) * Math.sin(circle.DegreesToRadians(φ)) - Math.tan(circle.DegreesToRadians(δ)) * Math.cos(circle.DegreesToRadians(φ)))))
|
48 |
|
49 | h = circle.RadiansToDegrees(Math.asin(Math.sin(circle.DegreesToRadians(φ)) * Math.sin(circle.DegreesToRadians(δ)) + Math.cos(circle.DegreesToRadians(φ)) * Math.cos(circle.DegreesToRadians(δ)) * Math.cos(circle.DegreesToRadians(H))))
|
50 | }
|
51 |
|
52 | return {
|
53 | E: E,
|
54 | A: Math.round(1000000 * A) / 1000000,
|
55 | h: Math.round(1000000 * h) / 1000000
|
56 | }
|
57 | }
|
58 |
|
59 | function positionEarth (JDE) {
|
60 |
|
61 | const τ = (JDE - 2451545) / 365250
|
62 |
|
63 | const L = circle.normalizedRadians(computeVSOP87(earthVSOP87D.L, τ))
|
64 | const B = computeVSOP87(earthVSOP87D.B, τ)
|
65 | const R = computeVSOP87(earthVSOP87D.R, τ)
|
66 |
|
67 | return {
|
68 | L: circle.RadiansToDegrees(L),
|
69 | B: circle.RadiansToDegrees(B),
|
70 | R: R
|
71 | }
|
72 | }
|
73 |
|
74 | function computeVSOP87 (obj, T) {
|
75 | let X = 0
|
76 | for (const α in obj) {
|
77 | let coeff = 0
|
78 | for (const β of obj[α]) {
|
79 | coeff += β.A * Math.cos(β.B + β.C * T)
|
80 | }
|
81 | X += coeff * Math.pow(T, α)
|
82 | }
|
83 |
|
84 | return X
|
85 | }
|