UNPKG

7.57 kBJavaScriptView Raw
1/* eslint standard/no-callback-literal:0 */
2/**
3 * @copyright 2013 Sonia Keys
4 * @copyright 2016 commenthol
5 * @license MIT
6 * @module perihelion
7 */
8/**
9 * Perihelion: Chapter 38, Planets in Perihelion and Aphelion.
10 *
11 * Functions Aphelion and Perihelion implement algorithms from the book
12 * to return approximate results.
13 *
14 * For accurate results, Meeus describes the general technique of
15 * interpolating from a precise ephemeris but does not give a complete
16 * algorithm. The algorithm implemented here for Aphelion2 and Perihelion2
17 * is to start with the approximate result and then crawl along the curve
18 * at the specified time resolution until the desired extremum is found.
19 * This algorithm slows down as higher accuracy is demanded. 1 day accuracy
20 * is generally quick for planets other than Neptune.
21 *
22 * Meeus doesn't give an algorithm to handle the double extrema of Neptune.
23 * The algorithm here is to pick starting points several years either side
24 * of the approximate date and follow the slopes inward. The consequence of
25 * starting farther from the extremum is that these functions are particularly
26 * slow for Neptune. They are offered here though as a simple implementation
27 * of Meeus's presentation in the book.
28 */
29import base from './base';
30import interp from './interpolation';
31
32/**
33 * Planet constants for first argument of Perihelion and Aphelion functions.
34 */
35var planets = {};
36export var mercury = planets.mercury = 0;
37export var venus = planets.venus = 1;
38export var earth = planets.earth = 2;
39export var mars = planets.mars = 3;
40export var jupiter = planets.jupiter = 4;
41export var saturn = planets.saturn = 5;
42export var uranus = planets.uranus = 6;
43export var neptune = planets.neptune = 7;
44export var embary = planets.embary = 8;
45
46/**
47 * Perihelion returns an approximate jde of the perihelion event nearest the given time.
48 *
49 * @param {perihelion.NAME} p - planet constant from above
50 * @param {Number} y - year number indicating a time near the perihelion event.
51 * @returns {Number} jde - time of the event
52 */
53export function perihelion(p, year) {
54 return ap(p, year, false, pf);
55}
56
57/**
58 * Aphelion returns an approximate jde of the aphelion event nearest the given time.
59 *
60 * @param {perihelion.NAME} p - planet constant from above
61 * @param {Number} y - year number indicating a time near the aphelion event.
62 * @returns {Number} jde - time of the event
63 */
64export function aphelion(p, year) {
65 return ap(p, year, true, af);
66}
67
68var pf = function pf(x) {
69 // (x float64) float64
70 return Math.floor(x + 0.5);
71};
72
73var af = function af(x) {
74 // (x float64) float64
75 return Math.floor(x) + 0.5;
76};
77
78var ap = function ap(p, y, a, f) {
79 // (p int, y float64, a bool, f func(float64) float64) float64
80 var i = p;
81 if (i === embary) {
82 i = earth;
83 }
84 var k = f(ka[i].a * (y - ka[i].b));
85 var j = base.horner(k, c[i]);
86 if (p === earth) {
87 var _c = ep;
88 if (a) {
89 _c = ea;
90 }
91 for (var _i = 0; _i < 5; _i++) {
92 j += _c[_i] * Math.sin((ec[_i].a + ec[_i].b * k) * Math.PI / 180);
93 }
94 }
95 return j;
96};
97
98var ka = [{ a: 4.15201, b: 2000.12 }, // Mercury
99{ a: 1.62549, b: 2000.53 }, // ...
100{ a: 0.99997, b: 2000.01 }, { a: 0.53166, b: 2001.78 }, { a: 0.0843, b: 2011.2 }, { a: 0.03393, b: 2003.52 }, { a: 0.0119, b: 2051.1 }, // Neptune
101{ a: 0.00607, b: 2047.5 // EMBary
102}];
103
104var c = [[2451590.257, 87.96934963], [2451738.233, 224.7008188, -0.0000000327], [2451547.507, 365.2596358, 0.0000000156], [2452195.026, 686.9957857, -0.0000001187], [2455636.936, 4332.897065, 0.0001367], [2452830.12, 10764.21676, 0.000827], [2470213.5, 30694.8767, -0.00541], [2468895.1, 60190.33, 0.03429]];
105
106var ec = [{ a: 328.41, b: 132.788585 }, { a: 316.13, b: 584.903153 }, { a: 346.2, b: 450.380738 }, { a: 136.95, b: 659.306737 }, { a: 249.52, b: 329.653368 }];
107
108var ep = [1.278, -0.055, -0.091, -0.056, -0.045];
109var ea = [-1.352, 0.061, 0.062, 0.029, 0.031];
110
111/**
112 * Perihelion2 returns the perihelion event nearest the given time.
113 *
114 * @param {planetposition.Planet} planet - VSOP87 planet (EMBary is not allowed)
115 * @param {Number} year - (float) decimal year number near the perihelion event
116 * @param {Number} precision - desired precision of the time result, in days
117 * @param {Function} [cb] - callback function for asynchronous processing `cb([jde, r])`
118 * @returns {Array} [jde, r]
119 * {Number} jde - time of the event
120 * {Number} r - the distance of the planet from the Sun in AU.
121 */
122export function perihelion2(planet, year, precision, cb) {
123 return ap2(planets[planet.name], year, precision, planet, false, pf, cb);
124}
125
126/**
127 * Aphelion2 returns the aphelion event nearest the given time.
128 *
129 * @param {planetposition.Planet} planet - VSOP87 planet (EMBary is not allowed)
130 * @param {Number} year - (float) decimal year number near the perihelion event
131 * @param {Number} precision - desired precision of the time result, in days
132 * @param {Function} [cb] - callback function for asynchronous processing `cb([jde, r])`
133 * @returns {Array} [jde, r]
134 * {Number} jde - time of the event
135 * {Number} r - the distance of the planet from the Sun in AU.
136 */
137export function aphelion2(planet, year, precision, cb) {
138 return ap2(planets[planet.name], year, precision, planet, true, af, cb);
139}
140
141if (typeof setImmediate !== 'function') {
142 var _setImmediate = setTimeout; // eslint-disable-line no-unused-vars
143}
144
145var ap2 = function ap2(p, y, d, v, a, f, cb) {
146 var j1 = ap(p, y, a, f);
147 if (p !== neptune) {
148 return ap2a(j1, d, a, v, cb);
149 }
150 // handle the double extrema of Neptune
151 if (cb) {
152 ap2a(j1 - 5000, d, a, v, function (_ref) {
153 var j0 = _ref[0],
154 r0 = _ref[1];
155
156 ap2a(j1 + 5000, d, a, v, function (_ref2) {
157 var j2 = _ref2[0],
158 r2 = _ref2[1];
159
160 if (r0 > r2 === a) {
161 cb([j0, r0]);
162 return;
163 }
164 cb([j2, r2]);
165 });
166 });
167 } else {
168 var _ap2a = ap2a(j1 - 5000, d, a, v),
169 j0 = _ap2a[0],
170 r0 = _ap2a[1];
171
172 var _ap2a2 = ap2a(j1 + 5000, d, a, v),
173 j2 = _ap2a2[0],
174 r2 = _ap2a2[1];
175
176 if (r0 > r2 === a) {
177 return [j0, r0];
178 }
179 return [j2, r2];
180 }
181};
182
183var ap2a = function ap2a(j1, d, a, v, cb) {
184 var j0 = j1 - d;
185 var j2 = j1 + d;
186 var rr = new Array(3);
187 rr[1] = v.position2000(j1).range;
188 rr[0] = v.position2000(j0).range;
189 rr[2] = v.position2000(j2).range;
190
191 function end() {
192 var l = new interp.Len3(j0, j2, rr);
193
194 var _l$extremum = l.extremum(),
195 jde = _l$extremum[0],
196 r = _l$extremum[1];
197
198 return [jde, r];
199 }
200
201 function run() {
202 if (a) {
203 if (rr[1] > rr[0] && rr[1] > rr[2]) {
204 cb && cb(end());
205 return true;
206 }
207 } else {
208 if (rr[1] < rr[0] && rr[1] < rr[2]) {
209 cb && cb(end());
210 return true;
211 }
212 }
213 if (rr[0] < rr[2] === a) {
214 j0 = j1;
215 j1 = j2;
216 j2 += d;
217 rr[0] = rr[1];
218 rr[1] = rr[2];
219 rr[2] = v.position2000(j2).range;
220 } else {
221 j2 = j1;
222 j1 = j0;
223 j0 -= d;
224 rr[2] = rr[1];
225 rr[1] = rr[0];
226 rr[0] = v.position2000(j0).range;
227 }
228 if (cb) {
229 setImmediate(run, 0);
230 }
231 }
232
233 if (cb) {
234 run();
235 } else {
236 for (;;) {
237 if (run()) {
238 return end();
239 }
240 }
241 }
242};
243
244export default {
245 mercury: mercury,
246 venus: venus,
247 earth: earth,
248 mars: mars,
249 jupiter: jupiter,
250 saturn: saturn,
251 uranus: uranus,
252 neptune: neptune,
253 embary: embary,
254 perihelion: perihelion,
255 aphelion: aphelion,
256 perihelion2: perihelion2,
257 aphelion2: aphelion2
258};
\No newline at end of file