PageSourceSearch

https://agsattrack.com/js/classes/planets.js

js agsattrack.com collected 2026-09-25 22:31:27 UTC 61,087 bytes, 1,485 lines download raw bytes

1/*
2Copyright 2012 Alex Greenland
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17//***************************************************
18//the following scripts are used by andi boesch 2008
19//as basic algorithms in the astro tools:
20//http://www.cybervisuals.ch/astro
21//***************************************************
22
23;var AGPLANETS = function() {
24    'usde strict';
25    
26    function sunxyz(jday) {
27        // return x,y,z ecliptic coordinates, distance, true longitude
28        // days counted from 1999 Dec 31.0 UT
29        var d = jday - 2451543.5;
30        var w = 282.9404 + 4.70935E-5 * d;
31        // argument of perihelion
32        var e = 0.016709 - 1.151E-9 * d;
33        var M = rev(356.0470 + 0.9856002585 * d);
34        // mean anomaly
35        var E = M + e * RAD2DEG * sind(M) * (1.0 + e * cosd(M));
36        var xv = cosd(E) - e;
37        var yv = Math.sqrt(1.0 - e * e) * sind(E);
38        var v = atan2d(yv, xv);
39        // true anomaly
40        var r = Math.sqrt(xv * xv + yv * yv);
41        // distance
42        var lonsun = rev(v + w);
43        // true longitude
44        var xs = r * cosd(lonsun);
45        // rectangular coordinates, zs = 0 for sun
46        var ys = r * sind(lonsun);
47        return new Array(xs, ys, 0, r, lonsun, 0);
48    }
49    
50    function SunAlt(jday, obs) {
51        // return alt, az, time angle, ra, dec, ecl. long. and lat=0, illum=1, 0,
52        // dist, brightness
53        var sdat = sunxyz(jday);
54        var ecl = 23.4393 - 3.563E-7 * (jday - 2451543.5);
55        var xe = sdat[0];
56        var ye = sdat[1] * cosd(ecl);
57        var ze = sdat[1] * sind(ecl);
58        var ra = rev(atan2d(ye, xe));
59        var dec = atan2d(ze, Math.sqrt(xe * xe + ye * ye));
60        var topo = radec2aa(ra, dec, jday, obs);
61        return new Array(topo[0], topo[1], topo[2], ra, dec, sdat[4], 0, 1, 0,
62                sdat[3], -26.74);
63    }
64    
65    // Sun rise and set times (if twilight==-0.833) or desired twilight time. Return
66    // julian days
67    function sunrise(obs, twilight) {
68        // obs is a reference variable make a copy
69        var obscopy = new Object();
70        for ( var i in obs) {
71            obscopy[i] = obs[i];
72        }
73        obscopy.hours = 12;
74        obscopy.minutes = 0;
75        obscopy.seconds = 0;
76        var riseset = new Array(0.0, 0.0, false, 0.0, 0.0);
77        var lst = local_sidereal(obscopy);
78        var jday = jd(obscopy);
79        var radec = SunAlt(jday, obscopy);
80        var ra = radec[3];
81        var dec = radec[4];
82        var UTsun = 12.0 + ra / 15.0 - lst;
83        if (UTsun < 0.0) {
84            UTsun += 24.0;
85        }
86        if (UTsun > 24.0) {
87            UTsun -= 24.0;
88        }
89        var cosLHA = (sind(twilight) - sind(obs.latitude) * sind(dec))
90                / (cosd(obs.latitude) * cosd(dec));
91        // Check for midnight sun and midday night. "riseset[2]" false if no rise
92        // and set found
93        riseset[2] = false;
94        if (cosLHA <= 1.0 && cosLHA >= -1.0) {
95            // rise/set times allowing for not today.
96            riseset[2] = true;
97            var lha = acosd(cosLHA) / 15.0;
98            if ((UTsun - lha) < 0.0) {
99                var rtime = 24.0 + UTsun - lha;
100            } else {
101                var rtime = UTsun - lha;
102            }
103            riseset[0] = jday + rtime / 24.0 - 0.5;
104            if ((UTsun + lha) > 24.0) {
105                var stime = UTsun + lha - 24.0;
106            } else {
107                var stime = UTsun + lha;
108                riseset[4] = stime;
109            }
110            riseset[1] = jday + stime / 24.0 - 0.5;
111            // riseset[3] and [4] are times in UT hours
112            riseset[3] = rtime;
113            riseset[4] = stime;
114        }
115        return (riseset);
116    }
117    
118    function MoonPos(jday, obs) {
119        // MoonPos calculates the Moon position and distance, based on Meeus chapter
120        // 47
121        // and the illuminated percentage from Meeus equations 48.4 and 48.1
122        // OPN: This version of MoonPos calculates the position to a precision of
123        // about 2' or so
124        // All T^2, T^3 and T^4 terms skipped. NB: Time is not taken from obs but
125        // from jday (julian day)
126        // Returns alt, az, hour angle, ra, dec (geocentr!), eclip. long and lat
127        // (geocentr!),
128        // illumination, distance, brightness and phase angle
129        var T = (jday - 2451545.0) / 36525;
130        // Moons mean longitude L'
131        var LP = rev(218.3164477 + 481267.88123421 * T);
132        // Moons mean elongation
133        var D = rev(297.8501921 + 445267.1114034 * T);
134        // Suns mean anomaly
135        var M = rev(357.5291092 + 35999.0502909 * T);
136        // Moons mean anomaly M'
137        var MP = rev(134.9633964 + 477198.8675055 * T);
138        // Moons argument of latitude
139        var F = rev(93.2720950 + 483202.0175233 * T);
140        // The "further arguments" A1, A2 and A3 and the term E have been ignored
141        // Sum of most significant terms from table 45.A and 45.B (terms less than
142        // 0.004 deg / 40 km dropped)
143        var Sl = 6288774 * sind(MP) + 1274027 * sind(2 * D - MP) + 658314
144                * sind(2 * D) + 213618 * sind(2 * MP) - 185116 * sind(M) - 114332
145                * sind(2 * F) + 58793 * sind(2 * D - 2 * MP) + 57066
146                * sind(2 * D - M - MP) + 53322 * sind(2 * D + MP) + 45758
147                * sind(2 * D - M) - 40923 * sind(M - MP) - 34720 * sind(D) - 30383
148                * sind(M + MP) + 15327 * sind(2 * D - 2 * F) - 12528
149                * sind(MP + 2 * F) + 10980 * sind(MP - 2 * F) + 10675
150                * sind(4 * D - MP) + 10034 * sind(3 * MP) + 8548
151                * sind(4 * D - 2 * MP) - 7888 * sind(2 * D + M - MP) - 6766
152                * sind(2 * D + M) - 5163 * sind(D - MP) + 4987 * sind(D + M) + 4036
153                * sind(2 * D - M + MP);
154        var Sb = 5128122 * sind(F) + 280602 * sind(MP + F) + 277602 * sind(MP - F)
155                + 173237 * sind(2 * D - F) + 55413 * sind(2 * D - MP + F) + 46271
156                * sind(2 * D - MP - F) + 32573 * sind(2 * D + F) + 17198
157                * sind(2 * MP + F) + 9266 * sind(2 * D + MP - F) + 8822
158                * sind(2 * MP - F) + 8216 * sind(2 * D - M - F) + 4324
159                * sind(2 * D - 2 * MP - F) + 4200 * sind(2 * D + MP + F);
160        var Sr = (-20905355) * cosd(MP) - 3699111 * cosd(2 * D - MP) - 2955968
161                * cosd(2 * D) - 569925 * cosd(2 * MP) + 246158
162                * cosd(2 * D - 2 * MP) - 152138 * cosd(2 * D - M - MP) - 170733
163                * cosd(2 * D + MP) - 204586 * cosd(2 * D - M) - 129620
164                * cosd(M - MP) + 108743 * cosd(D) + 104755 * cosd(M + MP) + 79661
165                * cosd(MP - 2 * F) + 48888 * cosd(M);
166        // geocentric longitude, latitude
167        var mglong = rev(LP + Sl / 1000000.0);
168        var mglat = Sb / 1000000.0;
169        // Obliquity of Ecliptic
170        var obl = 23.4393 - 3.563E-7 * (jday - 2451543.5);
171        var ra = rev(atan2d(sind(mglong) * cosd(obl) - tand(mglat) * sind(obl),
172                cosd(mglong)));
173        var dec = asind(sind(mglat) * cosd(obl) + cosd(mglat) * sind(obl)
174                * sind(mglong));
175
176        var moondat = radec2aa(ra, dec, jday, obs);
177        // phase angle (48.4)
178        var pa = Math.abs(180.0 - D - 6.289 * sind(MP) + 2.100 * sind(M) - 1.274
179                * sind(2 * D - MP) - 0.658 * sind(2 * D) - 0.214 * sind(2 * MP)
180                - 0.11 * sind(D));
181        var k = (1 + cosd(pa)) / 2;
182        var mr = Math.round(385000.56 + Sr / 1000.0);
183        var h = moondat[0];
184        // correct for parallax, equatorial horizontal parallax, see Meeus p. 337
185        h -= asind(6378.14 / mr) * cosd(h);
186        // brightness, use Paul Schlyter's formula (based on common phase law for
187        // Moon)
188        var sdat = sunxyz(jday);
189        var r = sdat[3];
190        // Earth (= Moon) distance to Sun in AU
191        var R = mr / 149598000;
192        // Moon distance to Earth in AU
193        var mag = 0.23 + 5 * log10(r * R) + 0.026 * pa + 4.0E-9 * pa * pa * pa * pa;
194        return new Array(h, moondat[1], moondat[2], ra, dec, mglong, mglat, k, r,
195                mr, mag);
196    }
197
198    function radec2aa(ra, dec, jday, obs) {
199        // Convert ra/dec to alt/az, also return hour angle, azimut = 0 when north
200        // DOES NOT correct for parallax!
201        // TH0=Greenwich sid. time (eq. 12.4), H=hour angle (chapter 13)
202        var TH0 = 280.46061837 + 360.98564736629 * (jday - 2451545.0);
203        var H = rev(TH0 - obs.longitude - ra);
204        var alt = asind(sind(obs.latitude) * sind(dec) + cosd(obs.latitude)
205                * cosd(dec) * cosd(H));
206        var az = atan2d(sind(H), (cosd(H) * sind(obs.latitude) - tand(dec)
207                * cosd(obs.latitude)));
208        return new Array(alt, rev(az + 180.0), H);
209    }
210
211    function place(name, latitude, ns, longitude, we, zone, dss, dse) {
212        this.name = name;
213        this.latitude = latitude;
214        this.ns = ns;
215        this.longitude = longitude;
216        this.we = we;
217        this.zone = zone;
218        this.dss = dss;
219        this.dse = dse;
220    }
221    
222    // A selection of places
223    // Please leave Greenwich in the first entry as the default
224    // The second entry is my home town, I suggest you change it to yours
225    // is you keep a copy for your personal use.
226    // This database is based on Peter Hayes' original database with several places
227    // added
228    var atlas = new Array(new place("UK:Greenwich", "51:28:38", 0, "00:00:00", 0,
229            0, "3:5:0", "10:5:0"), new place("NL:Rijswijk", "52:02:00", 0,
230            "4:19:00", 1, -60, "3:5:0", "10:5:0"), new place("AT:Vienna",
231            "48:13:00", 0, "16:22:00", 1, -60, "3:5:0", "10:5:0"),
232            new place("AU:Melbourne", "37:48:00", 1, "144:58:00", 1, -600,
233                    "10:5:0", "03:5:0"), new place("AU:Perth", "31:58:00", 1,
234                    "115:49:00", 1, -480, "10:5:0", "03:5:0"), new place(
235                    "BE:Brussels", "50:50:00", 0, "4:21:00", 1, -60, "3:5:0",
236                    "10:5:0"), new place("BR:Rio de Janeiro", "22:54:00", 1,
237                    "43:16:00", 0, 180, "", ""), new place("CA:Calgary",
238                    "51:03:00", 0, "114:05:00", 0, 420, "04:1:0", "10:5:0"),
239            new place("CA:Halifax", "44:35:00", 0, "63:39:00", 0, 240, "04:1:0",
240                    "10:5:0"), new place("CA:Toronto", "43:39:00", 0, "79:23:00",
241                    0, 300, "04:1:0", "10:5:0"), new place("CH:Zurich", "47:22:40",
242                    0, "08:33:04", 1, -60, "3:5:0", "10:5:0"), new place(
243                    "CL:Santiago", "33:30:00", 1, "70:40:00", 0, 240, "10:5:0",
244                    "03:5:0"), new place("DE:Berlin", "52:32:00", 0, "13:25:00", 1,
245                    -60, "3:5:0", "10:5:0"), new place("DE:Frankfurt/Main",
246                    "50:06:00", 0, "8:41:00", 1, -60, "3:5:0", "10:5:0"),
247            new place("DE:Hamburg", "53:33:00", 0, "10:00:00", 1, -60, "3:5:0",
248                    "10:5:0"), new place("DE:Munich", "48:08:00", 0, "11:35:00", 1,
249                    -60, "3:5:0", "10:5:0"), new place("DK:Copenhagen", "55:43:00",
250                    0, "12:34:00", 1, -60, "3:5:0", "10:5:0"), new place(
251                    "DK:Kolding", "55:31:00", 0, "9:29:00", 1, -60, "3:5:0",
252                    "10:5:0"), new place("DK:Aalborg", "57:03:00", 0, "9:51:00", 1,
253                    -60, "3:5:0", "10:5:0"), new place("DK:Ã…rhus", "56:10:00", 0,
254                    "10:13:00", 1, -60, "3:5:0", "10:5:0"), new place("EG:Cairo",
255                    "30:03:00", 0, "31:15:00", 1, -120, "", ""), new place(
256                    "ES:Madrid", "40:25:00", 0, "03:42:00", 0, -60, "3:5:0",
257                    "10:5:0"), new place("ES:Malaga", "36:43:00", 0, "04:25:00", 0,
258                    -60, "3:5:0", "10:5:0"), new place("ES:Las Palmas", "28:08:00",
259                    0, "15:27:00", 0, 60, "3:5:0", "10:5:0"), new place(
260                    "FI:Helsinki", "60:08:00", 0, "25:00:00", 1, -120, "3:5:0",
261                    "10:5:0"), new place("FR:Bordeaux", "44:50:00", 0, "0:34:00",
262                    0, -60, "3:5:0", "10:5:0"), new place("FR:Brest", "48:24:00",
263                    0, "4:30:00", 0, -60, "3:5:0", "10:5:0"), new place("FR:Lille",
264                    "50:38:00", 0, "03:04:00", 1, -60, "3:5:0", "10:5:0"),
265            new place("FR:Lyon", "45:46:00", 0, "04:50:00", 1, -60, "3:5:0",
266                    "10:5:0"), new place("FR:Marseille", "43:18:00", 0, "5:22:00",
267                    1, -60, "3:5:0", "10:5:0"), new place("FR:Paris", "48:48:00",
268                    0, "02:14:00", 1, -60, "3:5:0", "10:5:0"), new place(
269                    "FR:Puimichel", "43:58:00", 0, "06:01:00", 1, -60, "3:5:0",
270                    "10:5:0"), new place("FR:Strasbourg", "48:35:00", 0, "7:45:00",
271                    1, -60, "3:5:0", "10:5:0"), new place("GL:Nuuk", "64:15:00", 0,
272                    "51:34:00", 0, 180, "3:5:0", "10:5:0"), new place("GR:Athens",
273                    "38:00:00", 0, "23:44:00", 1, -120, "3:5:0", "10:5:0"),
274            new place("HK:Hong Kong", "22:15:00", 0, "114:11:00", 1, -480, "", ""),
275            new place("HR:Zagreb", "45:48:00", 0, "15:58:00", 1, -60, "3:5:0",
276                    "10:5:0"), new place("IE:Dublin", "53:19:48", 0, "06:15:00", 0,
277                    0, "3:5:0", "10:5:0"), new place("IN:New Delhi", "28:22:00", 0,
278                    "77:13:00", 1, -330, "", ""), new place("IQ:Baghdad",
279                    "33:20:00", 0, "44:26:00", 1, -180, "", ""), new place(
280                    "IR:Teheran", "35:44:00", 0, "51:30:00", 1, -210, "", ""),
281            new place("IS:Reykjavik", "64:09:00", 0, "21:58:00", 0, 60, "3:5:0",
282                    "10:5:0"), new place("IT:Milan", "45:28:00", 0, "9:12:00", 1,
283                    -60, "3:5:0", "10:5:0"), new place("IT:Palermo", "38:08:00", 0,
284                    "13:23:00", 1, -60, "3:5:0", "10:5:0"), new place("IT:Rome",
285                    "41:53:00", 0, "12:30:00", 1, -60, "3:5:0", "10:5:0"),
286            new place("JP:Tokyo", "35:70:00", 0, "139:46:00", 1, -540, "3:5:0",
287                    "10:5:0"), new place("LU:Luxembourg", "49:36:00", 0, "6:09:00",
288                    1, -60, "3:5:0", "10:5:0"), new place("NL:Amsterdam",
289                    "52:22:23", 0, "4:53:33", 1, -60, "3:5:0", "10:5:0"),
290            new place("NL:Apeldoorn", "52:13:00", 0, "5:57:00", 1, -60, "3:5:0",
291                    "10:5:0"), new place("NL:Maastricht", "50:51:00", 0, "5:04:00",
292                    1, -60, "3:5:0", "10:5:0"), new place("NL:Groningen",
293                    "53:13:00", 0, "6:33:00", 1, -60, "3:5:0", "10:5:0"),
294            new place("NL:The Hague", "52:05:00", 0, "4:29:00", 1, -60, "3:5:0",
295                    "10:5:0"), new place("NL:Utrecht", "52:05:10", 0, "05:07:45",
296                    1, -60, "3:5:0", "10:5:0"), new place("NO:Bergen", "60:21:00",
297                    0, "5:20:00", 1, -60, "3:5:0", "10:5:0"), new place("NO:Oslo",
298                    "59:56:00", 0, "10:45:00", 1, -60, "3:5:0", "10:5:0"),
299            new place("NO:Tromsø", "69:70:00", 0, "19:00:00", 1, -60, "3:5:0",
300                    "10:5:0"), new place("NZ:Wellington", "41:17:00", 1,
301                    "174:47:00", 1, -720, "10:5:0", "03:5:0"), new place(
302                    "PL:Warszawa", "52:15:00", 0, "21:00:00", 1, -60, "3:5:0",
303                    "10:5:0"), new place("PT:Faro", "37:01:00", 0, "7:56:00", 0, 0,
304                    "3:5:0", "10:5:0"), new place("PT:Lisbon", "38:44:00", 0,
305                    "9:08:00", 0, 0, "3:5:0", "10:5:0"), new place("PR:San Juan",
306                    "18:28:00", 0, "66:08:00", 0, 240, "04:1:0", "10:5:0"),
307            new place("RO:Bucharest", "44:25:00", 0, "26:07:00", 1, -120, "3:5:0",
308                    "10:5:0"), new place("RU:Irkutsk", "52:18:00", 0, "104:15:00",
309                    1, -480, "3:5:0", "10:5:0"), new place("RU:Moscow", "55:45:00",
310                    0, "37:35:00", 1, -180, "3:5:0", "10:5:0"), new place(
311                    "RU:Omsk", "55:00:00", 0, "73:22:00", 1, -360, "3:5:0",
312                    "10:5:0"), new place("SE:Gothenburg", "57:43:00", 0,
313                    "11:58:00", 1, -60, "3:5:0", "10:5:0"), new place(
314                    "SE:Stockholm", "59:35:00", 0, "18:06:00", 1, -60, "3:5:0",
315                    "10:5:0"), new place("SE:Luleå", "65:35:00", 0, "22:09:00", 1,
316                    -60, "3:5:0", "10:5:0"), new place("SG:Singapore", "01:20:00",
317                    0, "103:50:00", 1, -450, "", ""), new place("VC:Kingstown",
318                    "13:15:00", 0, "61:12:00", 0, 240, "", ""), new place(
319                    "UK:Birmingham", "52:30:00", 0, "01:49:48", 0, 0, "3:5:0",
320                    "10:5:0"), new place("UK:Belfast", "54:34:48", 0, "05:55:12",
321                    0, 0, "3:5:0", "10:5:0"), new place("UK:Cambridge", "52:10:00",
322                    0, "00:06:00", 0, 0, "3:5:0", "10:5:0"), new place(
323                    "UK:Cardiff", "51:30:00", 0, "03:12:00", 0, 0, "3:5:0",
324                    "10:5:0"), new place("UK:Edinburgh", "55:55:48", 0, "03:13:48",
325                    0, 0, "3:5:0", "10:5:0"), new place("UK:London", "51:30:00", 0,
326                    "00:10:12", 0, 0, "3:5:0", "10:5:0"), new place("US:Anchorage",
327                    "61:10:00", 0, "149:53:00", 0, 560, "04:1:0", "10:5:0"),
328            new place("US:Dallas", "32:48:00", 0, "96:48:00", 0, 360, "04:1:0",
329                    "10:5:0"), new place("US:Denver", "39:45:00", 0, "104:59:00",
330                    0, 420, "04:1:0", "10:5:0"), new place("US:Honolulu",
331                    "21:19:00", 0, "157:86:00", 0, 600, "04:1:0", "10:5:0"),
332            new place("US:Los Angeles", "34:03:15", 0, "118:14:28", 0, 480,
333                    "04:1:0", "10:5:0"), new place("US:Miami", "25:47:00", 0,
334                    "80:20:00", 0, 300, "04:1:0", "10:5:0"), new place(
335                    "US:Minneapolis", "44:58:01", 0, "93:15:00", 0, 360, "04:1:0",
336                    "10:5:0"), new place("US:Seattle", "47:36:00", 0, "122:19:00",
337                    0, 480, "04:1:0", "10:5:0"), new place("US:Washington DC",
338                    "38:53:51", 0, "77:00:33", 0, 300, "04:1:0", "10:5:0"),
339            new place("VC:St Vincent", "13:15:00", 0, "61:12:00", 0, 240, "", ""),
340            new place("ZA:Cape Town", "33:56:00", 1, "18:28:00", 1, -120, "", ""),
341            new place("ZM:Lusaka", "15:26:00", 1, "28:20:00", 1, -120, "", ""));
342
343    function observatory(place, year, month, day, hr, min, sec) {
344        // The observatory object holds local date and time,
345        // timezone correction in minutes with daylight saving if applicable,
346        // latitude and longitude (west is positive)
347        this.name = place.name;
348        this.year = year;
349        this.month = month;
350        this.day = day;
351        this.hours = hr;
352        this.minutes = min;
353        this.seconds = sec;
354        this.tz = place.tz;
355        this.dst = false;
356        // is it DST?
357        this.latitude = place.latitude;
358        this.longitude = place.longitude;
359    }
360    // The default observatory (Greenwich noon Jan 1 2000)
361    // changed by user setting place and time from menu
362    var observer = new observatory(atlas[0], 2000, 1, 1, 12, 0, 0);
363    // Site name returns name and latitude / longitude as a string
364    function sitename() {
365        var sname = observer.name;
366        var latd = Math.abs(observer.latitude) + 0.00001;
367        var latdi = Math.floor(latd);
368        sname += ((latdi < 10) ? " 0" : " ") + latdi;
369        latm = 60 * (latd - latdi);
370        latmi = Math.floor(latm);
371        sname += ((latmi < 10) ? ":0" : ":") + latmi;
372        // lats=60*(latm-latmi); latsi=Math.floor(lats);
373        // sname+=((latsi < 10) ? ":0" : ":") + latsi;
374        sname += ((observer.latitude >= 0) ? " N, " : " S, ");
375        var longd = Math.abs(observer.longitude) + 0.00001;
376        var longdi = Math.floor(longd);
377        sname += ((longdi < 10) ? "0" : "") + longdi;
378        longm = 60 * (longd - longdi);
379        longmi = Math.floor(longm);
380        sname += ((longmi < 10) ? ":0" : ":") + longmi;
381        // longs=60*(longm-longmi); longsi=Math.floor(longs);
382        // sname+=((longsi < 10) ? ":0" : ":") + longsi;
383        sname += ((observer.longitude >= 0) ? " W" : " E");
384        return sname;
385    }
386    // sitename()
387    function checkdst(obs) {
388        // Check DST is an attempt to check daylight saving, its not perfect.
389        // Returns 0 or -60 that is amount to remove to get to zone time.
390        // this function is now only called when selecting a place from the dropdown
391        // list. No dst check when updating the time!
392        // We only know daylight saving if in the atlas
393        if ((tbl.Place.selectedIndex < 0)
394                || (tbl.Place.selectedIndex >= atlas.length)) {
395            return 0;
396        }
397        var dss = atlas[tbl.Place.selectedIndex].dss;
398        var dse = atlas[tbl.Place.selectedIndex].dse;
399        var ns = atlas[tbl.Place.selectedIndex].ns;
400        if (dss.length == 0) {
401            return 0;
402        }
403        if (dse.length == 0) {
404            return 0;
405        }
406        // parse the daylight saving start & end dates
407        var col1 = dss.indexOf(":");
408        var col2 = dss.lastIndexOf(":");
409        var col3 = dss.length;
410        var dssm = parseInt(dss.substring(0, col1), 10);
411        var dssw = parseInt(dss.substring(col1 + 1, col2), 10);
412        var dssd = parseInt(dss.substring(col2 + 1, col3), 10);
413        col1 = dse.indexOf(":");
414        col2 = dse.lastIndexOf(":");
415        col3 = dse.length;
416        var dsem = parseInt(dse.substring(0, col1), 10);
417        var dsew = parseInt(dse.substring(col1 + 1, col2), 10);
418        var dsed = parseInt(dse.substring(col2 + 1, col3), 10);
419        // Length of months
420        // year,month,day and day of week
421        var jdt = jd0(obs.year, obs.month, obs.day);
422        var ymd = jdtocd(jdt);
423        // first day of month - we need to know day of week
424        var fymd = jdtocd(jdt - ymd[2] + 1);
425        // look for daylight saving / summertime changes
426        // first the simple month checks
427        // Test for the northern hemisphere
428        if (ns == 0) {
429            if ((ymd[1] > dssm) && (ymd[1] < dsem)) {
430                return -60;
431            }
432            if ((ymd[1] < dssm) || (ymd[1] > dsem)) {
433                return 0;
434            }
435        } else {
436            // Southern hemisphere, New years day is summer.
437            if ((ymd[1] > dssm) || (ymd[1] < dsem)) {
438                return -60;
439            }
440            if ((ymd[1] < dssm) && (ymd[1] > dsem)) {
441                return 0;
442            }
443        }
444        // check if we are in month of change over
445        if (ymd[1] == dssm) {
446            // month of start of summer time
447            // date of change over
448            var ddd = dssd - fymd[3] + 1;
449            ddd = ddd + 7 * dssw;
450            while (ddd > month_length[ymd[1] - 1]) {
451                ddd -= 7;
452            }
453            if (ymd[2] < ddd) {
454                return 0;
455            }
456            // assume its past the change time, its impossible
457            // to know if the change has occured.
458            return -60;
459        }
460        if (ymd[1] == dsem) {
461            // month of end of summer time
462            // date of change over
463            var ddd = dsed - fymd[3] + 1;
464            ddd = ddd + 7 * dsew;
465            while (ddd > month_length[ymd[1] - 1]) {
466                ddd -= 7;
467            }
468            if (ymd[2] < ddd) {
469                return -60;
470            }
471            // see comment above for start time
472            return 0;
473        }
474        return 0;
475    }
476    // checkdst()
477    function jd(obs) {
478        // The Julian date at observer time
479        var j = jd0(obs.year, obs.month, obs.day);
480        j += (obs.hours + ((obs.minutes + obs.tz) / 60.0) + (obs.seconds / 3600.0)) / 24;
481        return j;
482    }
483    // jd()
484    function local_sidereal(obs) {
485        // sidereal time in hours for observer
486        var res = g_sidereal(obs.year, obs.month, obs.day);
487        res += 1.00273790935 * (obs.hours + (obs.minutes + obs.tz + (obs.seconds / 60.0)) / 60.0);
488        res -= obs.longitude / 15.0;
489        while (res < 0) {
490            res += 24.0;
491        }
492        while (res > 24) {
493            res -= 24.0;
494        }
495        return res;
496    }
497    //
498    //
499    // ***************************************************
500    // part 3
501    //
502    // Various date and time functions
503    // Copyright Peter Hayes 1999-2001, Ole Nielsen 2002-2004
504    // must be updated using leapyear() if year changed
505    var month_length = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
506    var dow = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
507    function leapyear(year) {
508        var leap = false;
509        if (year % 4 == 0) {
510            leap = true;
511        }
512        if (year % 100 == 0) {
513            leap = false;
514        }
515        if (year % 400 == 0) {
516            leap = true;
517        }
518        return leap;
519    }
520    function jd0(year, month, day) {
521        // The Julian date at 0 hours(*) UT at Greenwich
522        // (*) or actual UT time if day comprises time as fraction
523        var y = year;
524        var m = month;
525        if (m < 3) {
526            m += 12;
527            y -= 1;
528        }
529        var a = Math.floor(y / 100);
530        var b = 2 - a + Math.floor(a / 4);
531        var j = Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1))
532                + day + b - 1524.5;
533        return j;
534    }
535    // jd0()
536    function jdtocd(jd) {
537        // The calendar date from julian date, see Meeus p. 63
538        // Returns year, month, day, day of week, hours, minutes, seconds
539        var Z = Math.floor(jd + 0.5);
540        var F = jd + 0.5 - Z;
541        if (Z < 2299161) {
542            var A = Z;
543        } else {
544            var alpha = Math.floor((Z - 1867216.25) / 36524.25);
545            var A = Z + 1 + alpha - Math.floor(alpha / 4);
546        }
547        var B = A + 1524;
548        var C = Math.floor((B - 122.1) / 365.25);
549        var D = Math.floor(365.25 * C);
550        var E = Math.floor((B - D) / 30.6001);
551        var d = B - D - Math.floor(30.6001 * E) + F;
552        if (E < 14) {
553            var month = E - 1;
554        } else {
555            var month = E - 13;
556        }
557        if (month > 2) {
558            var year = C - 4716;
559        } else {
560            var year = C - 4715;
561        }
562        var day = Math.floor(d);
563        var h = (d - day) * 24;
564        var hours = Math.floor(h);
565        var m = (h - hours) * 60;
566        var minutes = Math.floor(m);
567        var seconds = Math.round((m - minutes) * 60);
568        if (seconds >= 60) {
569            minutes = minutes + 1;
570            seconds = seconds - 60;
571        }
572        if (minutes >= 60) {
573            hours = hours + 1;
574            minutes = 0;
575        }
576        var dw = Math.floor(jd + 1.5) - 7 * Math.floor((jd + 1.5) / 7);
577        return new Array(year, month, day, dw, hours, minutes, seconds);
578    }
579    // jdtocd()
580    function g_sidereal(year, month, day) {
581        // sidereal time in hours for Greenwich
582        var T = (jd0(year, month, day) - 2451545.0) / 36525;
583        var res = 100.46061837 + T
584                * (36000.770053608 + T * (0.000387933 - T / 38710000.0));
585        return rev(res) / 15.0;
586    }
587    //
588    //
589    // ***************************************************
590    // part 4
591    //
592    // Utility functions
593    // Copyright Ole Nielsen 2002-2004, Peter Hayes 1999-2001
594    function datestring(obs) {
595        // datestring provides a locale independent format
596        var datestr = "";
597        datestr += obs.year;
598        datestr += ((obs.month < 10) ? ":0" : ":") + obs.month;
599        datestr += ((obs.day < 10) ? ":0" : ":") + obs.day;
600        return datestr;
601    }
602    // end datestring()
603    function datestring2(year, month, day) {
604        var datestr = "";
605        datestr += year;
606        datestr += ((month < 10) ? ":0" : ":") + month;
607        datestr += ((day < 10) ? ":0" : ":") + day;
608        return datestr;
609    }
610    // end datestring2()
611    function adjustTime(obs, amount) {
612        // update date and time, amount is in minutes (may be negative)
613        // added 2004
614        month_length[1] = leapyear(obs.year) ? 29 : 28;
615        if (amount < 0) {
616            amount = Math.abs(amount);
617            obs.minutes -= amount % 60;
618            amount = Math.floor(amount / 60.0);
619            obs.hours -= amount % 24;
620            amount = Math.floor(amount / 24.0);
621            obs.day -= amount;
622            if (obs.minutes < 0) {
623                obs.minutes += 60;
624                obs.hours -= 1;
625            }
626            if (obs.hours < 0) {
627                obs.hours += 24;
628                obs.day -= 1;
629            }
630            while (obs.day < 1) {
631                obs.day += month_length[obs.month - 2 + (obs.month 
631== 1 ? 12 : 0)];
632                obs.month -= 1;
633                if (obs.month == 0) {
634                    obs.year -= 1;
635                    obs.month = 12;
636                    month_length[1] = (leapyear(obs.year) ? 29 : 28);
637                }
638            }
639        } else {
640            obs.minutes += amount % 60;
641            amount = Math.floor(amount / 60.0);
642            obs.hours += amount % 24;
643            amount = Math.floor(amount / 24.0);
644            obs.day += amount;
645            if (obs.minutes > 59) {
646                obs.minutes -= 60;
647                obs.hours += 1;
648            }
649            if (obs.hours > 23) {
650                obs.hours -= 24;
651                obs.day += 1;
652            }
653            while (obs.day > month_length[obs.month - 1]) {
654                obs.day -= month_length[obs.month - 1];
655                obs.month += 1;
656                if (obs.month == 13) {
657                    obs.year += 1;
658                    obs.month = 1;
659                    month_length[1] = (leapyear(obs.year) ? 29 : 28);
660                }
661            }
662        }
663    }
664    // end adjustTime()
665    function hmsstring(t) {
666        // the caller must add a leading + if required.
667        var hours = Math.abs(t);
668        var minutes = 60.0 * (hours - Math.floor(hours));
669        hours = Math.floor(hours);
670        var seconds = Math.round(60.0 * (minutes - Math.floor(minutes)));
671        minutes = Math.floor(minutes);
672        if (seconds >= 60) {
673            minutes += 1;
674            seconds -= 60;
675        }
676        if (minutes >= 60) {
677            hour += 1;
678            minutes -= 60;
679        }
680        if (hours >= 24) {
681            hours -= 24;
682        }
683        var hmsstr = (t < 0) ? "-" : "";
684        hmsstr = ((hours < 10) ? "0" : "") + hours;
685        hmsstr += ((minutes < 10) ? ":0" : ":") + minutes;
686        hmsstr += ((seconds < 10) ? ":0" : ":") + seconds;
687        return hmsstr;
688    }
689    // end hmsstring()
690    function hmstring(t, plus) {
691        // hmstring converts hours to a string (+/-)hours:minutes, used for relative
692        // time (TZ)
693        var hours = Math.abs(t);
694        var minutes = Math.round(60.0 * (hours - Math.floor(hours)));
695        hours = Math.floor(hours);
696        if (minutes >= 60) {
697            hours += 1;
698            minutes -= 60;
699        }
700        // minutes could be 60 due to rounding
701        if (hours >= 24) {
702            hours -= 24;
703        }
704        var hmstr = (t < 0) ? "-" : (plus ? "+" : "");
705        hmstr += ((hours < 10) ? "0" : "") + hours;
706        hmstr += ((minutes < 10) ? ":0" : ":") + minutes;
707        return hmstr;
708    }
709    // end hmstring()
710    function hmstring2(hours, minutes, seconds) {
711        // hmstring2 returns time as a string HH:MM (added 2004.01.02), seconds
712        // needed for rounding
713        if (seconds >= 30) {
714            minutes++;
715        }
716        if (minutes >= 60) {
717            hours++;
718            minutes = 0;
719        }
720        var timestr = ((hours < 10) ? "0" : "") + hours;
721        timestr += ((minutes < 10) ? ":0" : ":") + minutes;
722        return timestr;
723    }
724    // end hmstring2()
725    function dmsstring(d) {
726        // dmsstring converts lat/long angle to unsigned string d:m:s
727        var deg = Math.abs(d);
728        var minutes = 60.0 * (deg - Math.floor(deg));
729        deg = Math.floor(deg);
730        var seconds = Math.round(60.0 * (minutes - Math.floor(minutes)));
731        minutes = Math.floor(minutes);
732        if (seconds >= 60) {
733            minutes += 1;
734            seconds -= 60;
735        }
736        if (minutes >= 60) {
737            deg += 1;
738            minutes -= 60;
739        }
740        hmsstr = ((deg < 10) ? "0" : "") + deg;
741        hmsstr += ((minutes < 10) ? ":0" : ":") + minutes;
742        hmsstr += ((seconds < 10) ? ":0" : ":") + seconds;
743        return hmsstr;
744    }
745    // end dmsstring()
746    function dmstring(d) {
747        // dmstring converts lat/long angle to unsigned string d:m
748        var deg = Math.abs(d);
749        var minutes = 60.0 * (deg - Math.floor(deg));
750        deg = Math.floor(deg);
751        var seconds = Math.round(60.0 * (minutes - Math.floor(minutes)));
752        minutes = Math.floor(minutes);
753        if (seconds >= 30) {
754            minutes += 1;
755        }
756        if (minutes >= 60) {
757            deg += 1;
758            minutes -= 60;
759        }
760        hmstr = ((deg < 10) ? "0" : "") + deg;
761        hmstr += ((minutes < 10) ? ":0" : ":") + minutes;
762        return hmstr;
763    }
764    // end dmstring()
765    function anglestring(a, circle, arcmin) {
766        // Return angle as degrees:minutes. 'circle' is true for range between 0 and
767        // 360
768        // and false for -90 to +90, if 'arcmin' use deg and arcmin symbols
769        var ar = Math.round(a * 60) / 60;
770        var deg = Math.abs(ar);
771        var min = Math.round(60.0 * (deg - Math.floor(deg)));
772        if (min >= 60) {
773            deg += 1;
774            min = 0;
775        }
776        var anglestr = "";
777        if (!circle) {
778            anglestr += (ar < 0 ? "-" : "+");
779        }
780        if (circle) {
781            anglestr += ((Math.floor(deg) < 100) ? "0" : "");
782        }
783        anglestr += ((Math.floor(deg) < 10) ? "0" : "") + Math.floor(deg);
784        if (arcmin) {
785            anglestr += ((min < 10) ? "&deg;0" : "&deg;") + (min) + "' ";
786        } else {
787            anglestr += ((min < 10) ? ":0" : ":") + (min);
788        }
789        return anglestr;
790    }
791    // end anglestring()
792    function fixnum(n, l, d) {
793        // convert float n to right adjusted string of length l with d digits after
794        // decimal point.
795        // the sign always requires one character, allow for that in l!
796        var m = 1;
797        for ( var i = 0; i < d; i++) {
798            m *= 10;
799        }
800        var n1 = Math.round(Math.abs(n) * m);
801        var nint = Math.floor(n1 / m);
802        var nfract = (n1 - m * nint) + "";
803        // force conversion to string
804        while (nfract.length < d) {
805            nfract = "0" + nfract;
806        }
807        var str = (n < 0 ? "-" : " ") + nint;
808        if (d > 0) {
809            str = str + "." + nfract;
810        }
811        while (str.length < l) {
812            str = " " + str;
813        }
814        return str;
815    }
816    // end fixnum()
817    function fixstr(str, l) {
818        // returns left-adjusted string of length l, pad with spaces or truncate as
819        // necessary
820        if (str.length > l) {
821            return str.substring(0, l);
822        }
823        while (str.length < l) {
824            str += " ";
825        }
826        return str;
827    }
828    // end fixstr()
829    function parsecol(str) {
830        // parsecol converts deg:min:sec or hr:min:sec to a number
831        var col1 = str.indexOf(":");
832        var col2 = str.lastIndexOf(":");
833        if (col1 < 0) {
834            return parseInt(str);
835        }
836        if (str.substring(0, 1) == "-") {
837            var res = parseInt(str.substring(1, col1), 10);
838        } else {
839            var res = parseInt(str.substring(0, col1), 10);
840        }
841        if (col2 > col1) {
842            res += (parseInt(str.substring(col1 + 1, col2), 10) / 60.0)
843                    + (parseInt(str.substring(col2 + 1, str.length), 10) / 3600.0);
844        } else {
845            res += (parseInt(str.substring(col1 + 1, str.length), 10) / 60.0);
846        }
847        if (str.substring(0, 1) == "-") {
848            return -res;
849        } else {
850            return res;
851        }
852    }
853    // end parsecol()
854    function interpol(n, y1, y2, y3) {
855        // interpolate y (Meeus 3.3)
856        var a = y2 - y1;
857        var b = y3 - y2;
858        var c = b - a;
859        return y2 + (n / 2) * (a + b + n * c);
860    }
861    function nzero(y1, y2, y3) {
862        // Calculate value of interpolation factor for which y=zero. n0 should be
863        // within [-1:1]
864        // Meeus formula (3.7)
865        var a = y2 - y1;
866        var b = y3 - y2;
867        var c = b - a;
868        var n0 = 0;
869        do {
870            dn0 = -(2 * y2 + n0 * (a + b + c * n0)) / (a + b + 2 * c * n0);
871            n0 += dn0;
872        } while (Math.abs(dn0) > 0.0001);
873        return n0;
874    }
875    // end nzero()
876    function nextrem(y1, y2, y3) {
877        // Calculate value of interpolation factor for which y reaches extremum
878        // (-1<n<1);
879        var a = y2 - y1;
880        var b = y3 - y2;
881        var c = b - a;
882        var nm = -(a + b) / (2 * c);
883        // (3.5)
884        return nm;
885    }
886    // end nextrem();
887    function isort(arr) {
888        // Sort 2D array in ascending order on first column of each element using
889        // insertion sort
890        for ( var c = 0; c < arr.length - 1; c++) {
891            var tmp = arr[c + 1];
892            var a = c;
893            while (a >= 0 && arr[a][0] > tmp[0]) {
894                arr[a + 1] = arr[a];
895                a--;
896            }
897            arr[a + 1] = tmp;
898        }
899    }
900    // end isort()
901    //
902    //
903    // ***************************************************
904    // part 5
905    //
906    // Extensions to the Math routines - Trig routines in degrees
907    // Copyright Peter Hayes 1999-2001, Ole Nielsen 2003-2004
908    var DEG2RAD = Math.PI / 180.0;
909    var RAD2DEG = 180.0 / Math.PI;
910    function rev(angle) {
911        return angle - Math.floor(angle / 360.0) * 360.0;
912    }
913    // 0<=a<360
914    function rev2(angle) {
915        var a = rev(angle);
916        return (a >= 180 ? a - 360.0 : a);
917    }
918    // -180<=a<180
919    function sind(angle) {
920        return Math.sin(angle * DEG2RAD);
921    }
922    function cosd(angle) {
923        return Math.cos(angle * DEG2RAD);
924    }
925    function tand(angle) {
926        return Math.tan(angle * DEG2RAD);
927    }
928    function asind(c) {
929        return RAD2DEG * Math.asin(c);
930    }
931    function acosd(c) {
932        return RAD2DEG * Math.acos(c);
933    }
934    function atand(c) {
935        return RAD2DEG * Math.atan(c);
936    }
937    function atan2d(y, x) {
938        return RAD2DEG * Math.atan2(y, x);
939    }
940    function log10(x) {
941        return Math.LOG10E * Math.log(x);
942    }
943    function sqr(x) {
944        return x * x;
945    }
946    function cbrt(x) {
947        return Math.pow(x, 1 / 3.0);
948    }
949    function SGN(x) {
950        return (x < 0) ? -1 : +1;
951    }
952    //
953    //
954    // ***************************************************
955    // part 6
956    //
957    // FUNCTIONS FOR FINDING EVENTS
958    //
959    // Copyright Ole Nielsen 2002-2004
960    // Please read copyright notice in astrotools2.html source
961    //
962    // 'Meeus' means "Astronomical Algorithms", 2nd ed. by Jean Meeus
963    // standard altitudes for rise and set
964    var H0SUN = -0.833;
965    var H0STAR = -0.583;
966    //
967    //
968    function findEvents(obj, jday, obs) {
969        // Version 2
970        // Calculate daily events (rise, transit, set etc) for one day starting at
971        // jday
972        // Returns chronological sorted array of records, each record comprising
973        // time [0<=t<1] relative to jday
974        // and event type. Event type codes are:
975        // 0: transit; -1/1: rise/set; -2/2: civ. twil. start/end; -3/3 naut twil;
976        // -4/4: astr twil
977        // The first record is different: Type code is 0 for object up, 1 for less
978        // than 6 deg below horizon etc
979        // The code is a little bit 'hairy'. Basically, it determines the nearest
980        // transit time of the
981        // object at each side of the middle of the time interval, and from these
982        // transit times it
983        // calculates rise and set times (and twilights for the Sun).
984        //
985        // reference horizon h0 for Moon depends on parallax, see Meeus p. 102
986        if (obj == MOON) {
987            bodies[obj].update(jday + 0.5, obs);
988            var par = asind(6378.14 / bodies[obj].dist);
989            var h0moon = 0.7275 * par - 0.567;
990        }
991        // rise/set altitude depends on object
992        var href0 = ((obj == SUN) ? H0SUN : H0STAR);
993        if (obj == MOON) {
994            href0 = h0moon;
995        }
996        // stores the various events in records of [t, type]
997        var events = new Array();
998        var count = 0;
999        // find situation at start of interval (not currently used by AstroTools but
1000        // needed by Skyplanner)
1001        bodies[obj].update(jday, obs);
1002        var altaz = radec2aa(bodies[obj].ra, bodies[obj].dec, jday, obs);
1003        var alt = altaz[0];
1004        var type = 4;
1005        // object is visible
1006        if (alt > href0) {
1007            type = 0;
1008        } else if (alt > -6) {
1009            // civil twilight
1010            type = 1;
1011        } else if (alt > -12) {
1012            // naut. twil.
1013            type = 2;
1014        } else if (alt > -18) {
1015            // astr. twil.
1016            type = 3;
1017        }
1018        events[count++] = new Array(0, type);
1019        bodies[obj].update(jday + 0.5, obs);
1020        var dec1 = bodies[obj].dec;
1021        var altaz = radec2aa(bodies[obj].ra, bodies[obj].dec, jday + 0.5, obs);
1022        // H is hour angle
1023        var H = altaz[2];
1024        // first transit approx.
1025        var m = -H / 360.0;
1026        // check for events around first and second transit
1027        for ( var i = 0; i < 2; i++) {
1028            bodies[obj].update(jday + 0.5 + m, obs);
1029            var altaz = radec2aa(bodies[obj].ra, bodies[obj].dec, jday + 0.5 + m,
1030                    obs);
1031            var H = altaz[2] > 180.0 ? altaz[2] - 360 : altaz[2];
1032            // correction to transit time (Meeus page 103)
1033            m0 = m - H / 360.0;
1034            if (m0 >= -0.5 && m0 < 0.5) {
1035                // save transit time
1036                events[count++] = new Array(m0 + 0.5, 0);
1037            }
1038            // find rise and set times (and start/end of twilights if sun)
1039            for ( var j = 0; j <= (obj == SUN ? 3 : 0); j++) {
1040                // href is the desired reference horizon
1041                var href = -6.0 * j;
1042                if (href == 0.0) {
1043                    href = href0;
1044                }
1045                // (Meeus 15.1)
1046                var cosH0 = (sind(href) - sind(obs.latitude) * sind(dec1))
1047                        / (cosd(obs.latitude) * cosd(dec1));
1048                if (cosH0 >= -1.0 && cosH0 <= 1.0) {
1049                    // this may miss occasional rises/sets in polar regions,
1050                    // especially for Moon
1051                    var H0 = acosd(cosH0);
1052                    // rise (Meeus 15.2)
1053                    var m1 = m0 - H0 / 360.0;
1054                    bodies[obj].update(jday + 0.5 + m1, obs);
1055                    var altaz = radec2aa(bodies[obj].ra, bodies[obj].dec, jday
1056                            + 0.5 + m1, obs);
1057                    H = altaz[2];
1058                    // correction to rise time
1059                    m1 += (altaz[0] - href)
1060                            / (360 * cosd(bodies[obj].dec) * cosd(obs.latitude) * sind(H));
1061                    // only keep event within interval of interest
1062                    if (m1 >= -0.5 && m1 < 0.5) {
1063                        events[count++] = new Array(m1 + 0.5, -j - 1);
1064                    }
1065                    // set
1066                    var m2 = m0 + H0 / 360.0;
1067                    bodies[obj].update(jday + 0.5 + m2, obs);
1068                    var altaz = radec2aa(bodies[obj].ra, bodies[obj].dec, jday
1069                            + 0.5 + m2, obs);
1070                    H = altaz[2];
1071                    // correction to set time
1072                    m2 += (altaz[0] - href)
1073                            / (360 * cosd(bodies[obj].dec) * cosd(obs.latitude) * sind(H));
1074                    if (m2 >= -0.5 && m2 < 0.5) {
1075                        events[count++] = new Array(m2 + 0.5, j + 1);
1076                    }
1077                }
1078            }
1079            // second transit approx.
1080            m += 1.0;
1081        }
1082        // end marker
1083        events[count++] = new Array(1.0, -9);
1084        // bring in chronological order
1085        isort(events);
1086        return events;
1087    }
1088    // end findEvents()
1089    //
1090    //
1091    // ***************************************************
1092    // part 7
1093    //
1094    // Functions for the planets
1095    // Copyright Ole Nielsen 2002-2004
1096    // Please read copyright notice in astrotools2.html source
1097    // Formulae and elements from Paul Schlyter's article "Computing planetary
1098    // positions" available at
1099    // http://hem.passagen.se/pausch/comp/ppcomp.html
1100    MERCURY = 0;
1101    VENUS = 1;
1102    EARTH = 2;
1103    MARS = 3;
1104    JUPITER = 4;
1105    SATURN = 5;
1106    URANUS = 6;
1107    NEPTUNE = 7;
1108    SUN = 9;
1109    MOON = 10;
1110    COMET = 15;
1111    USER = 20;
1112    // Planet diameters at 1 AU in arcsec (km for Moon)
1113    var ndiam = [ 6.72, 16.68, 1, 9.36, 196.88, 165.46, 70.04, 67.0, 1, 1919.3,
1114            716900000.0 ];
1115    // The planet object
1116    function planet(name, num, N, i, w, a, e, M) {
1117        this.name = name;
1118        this.num = num;
1119        this.N = N;
1120        // longitude of ascending node
1121        this.i = i;
1122        // inclination
1123        this.w = w;
1124        // argument of perihelion
1125        this.a = a;
1126        // semimajor axis
1127        this.e = e;
1128        // eccentricity
1129        this.M = M;
1130        // mean anomaly
1131    }
1132    // elements from Paul Schlyter
1133    var planets = new Array();
1134    planets[0] = new planet("Mercury", 0, new Array(48.3313, 3.24587E-5),
1135            new Array(7.0047, 5.00E-8), new Array(29.1241, 1.01444E-5), new Array(
1136                    0.387098, 0), new Array(0.205635, 5.59E-10), new Array(
1137                    168.6562, 4.0923344368));
1138    planets[1] = new planet("Venus  ", 1, new Array(76.6799, 2.46590E-5),
1139            new Array(3.3946, 2.75E-8), new Array(54.8910, 1.38374E-5), new Array(
1140                    0.723330, 0), new Array(0.006773, -1.302E-9), new Array(
1141                    48.0052, 1.6021302244));
1142    planets[2] = new planet("Earth  ", 2, new Array(0, 0), new Array(0, 0),
1143            new Array(0, 0), new Array(0.0, 0.0), new Array(0.0, 0.0), new Array(0,
1144                    0));
1145    planets[3] = new planet("Mars   ", 3, new Array(49.5574, 2.11081E-5),
1146            new Array(1.8497, -1.78E-8), new Array(286.5016, 2.92961E-5),
1147            new Array(1.523688, 0), new Array(0.093405, 2.516E-9), new Array(
1148                    18.6021, 0.5240207766));
1149    planets[4] = new planet("Jupiter", 4, new Array(100.4542, 2.76854E-5),
1150            new Array(1.3030, -1.557E-7), new Array(273.8777, 1.64505E-5),
1151            new Array(5.20256, 0), new Array(0.048498, 4.469E-9), new Array(
1152                    19.8950, 0.0830853001));
1153    planets[5] = new planet("Saturn ", 5, new Array(113.6634, 2.38980E-5),
1154            new Array(2.4886, -1.081E-7), new Array(339.3939, 2.97661E-5),
1155            new Array(9.55475, 0), new Array(0.055546, -9.499E-9), new Array(
1156                    316.9670, 0.0334442282));
1157    planets[6] = new planet("Uranus ", 6, new Array(74.0005, 1.3978E-5), new Array(
1158            0.7733, 1.9E-8), new Array(96.6612, 3.0565E-5), new Array(19.18171,
1159            -1.55E-8), new Array(0.047318, 7.45E-9), new Array(142.5905,
1160            0.011725806));
1161    planets[7] = new planet("Neptune", 7, new Array(131.7806, 3.0173E-5),
1162            new Array(1.7700, -2.55E-7), new Array(272.8461, -6.027E-6), new Array(
1163                    30.05826, 3.313E-8), new Array(0.008606, 2.15E-9), new Array(
1164                    260.2471, 0.005995147));
1165    // Body holds current data of planet, Sun or Moon), method .update(jday,obs)
1166    function Body(name, number, colour, colleft, colright) {
1167        this.name = name;
1168        this.number = number;
1169        this.colour = colour;
1170        this.colleft = colleft;
1171        this.colright = colright;
1172        this.alt = 0;
1173        this.az = 0;
1174        this.dec = 0;
1175        this.ra = 0;
1176        this.H = 0;
1177        this.eclon = 0;
1178        this.eclat = 0;
1179        this.illum = 1;
1180        this.r = 1;
1181        // heliocentric distance
1182        this.dist = 1;
1183        // geocentric distance
1184        this.mag = -1.0;
1185        this.elong = 0;
1186        this.pa = 0;
1187        this.phase = 1; // for Moon
1188        // position angle (elongation)
1189        this.update = updatePosition;
1190        this.elongupdate = updateElong;
1191    }
1192    
1193    bodies = new Array();
1194    bodies[0] = new Body("Mercury", MERCURY, 0, 24, 25);
1195    bodies[1] = new Body("Venus", VENUS, 1, 24, 25);
1196   // bodies[2] = new Body("Earth", 2, 3, 24, 25);
1197    bodies[2] = new Body("Mars", MARS, 3, 24, 25);
1198    bodies[3] = new Body("Jupiter", JUPITER, 4, 24, 25);
1199    bodies[4] = new Body("Saturn", SATURN, 5, 24, 25);
1200    bodies[5] = new Body("Uranus", URANUS, 6, 24, 25);
1201    bodies[6] = new Body("Neptune", NEPTUNE, 7, 24, 25);
1202   // bodies[8] = new Body("", 8, 0, 0, 0);
1203    bodies[7] = new Body("Sun", SUN, 9, 26, 27);
1204    bodies[8] = new Body("Moon", MOON, 10, 28, 29);
1205  //  bodies[COMET] = new Body("Comet  ", COMET, 2, 24, 25);
1206  //  bodies[20] = new Body("User object", USER, 2, 24, 25);
1207    function updatePosition(jday, obs) {
1208        // update body-object with current positions
1209        // elongation NOT calculated! (use updateElong for that)
1210        this.p = this.number;
1211        if (this.p == USER) {
1212            // fixed/user object
1213            var altaz = radec2aa(this.ra, this.dec, jday, obs);
1214            this.alt = altaz[0];
1215            this.az = altaz[1];
1216            this.H = altaz[2];
1217            return;
1218        }
1219        var dat = PlanetAlt(this.p, jday, obs);
1220        this.alt = dat[0];
1221        this.az = dat[1];
1222        this.H = dat[2];
1223        this.ra = dat[3];
1224        this.dec = dat[4] - (dat[4] > 180.0 ? 360 : 0);
1225        this.eclon = rev(dat[5]);
1226        this.eclat = dat[6];
1227        this.r = dat[8];
1228        this.dist = dat[9];
1229        this.illum = dat[7];
1230        this.mag = dat[10];
1231        
1232        this.x = dat[11];
1233        this.y = dat[12];
1234        this.z = dat[13];
1235     
1236        if (this.p === MOON) {
1237            var j;
1238            var ip, ag;
1239            ip = (jday + 4.867) / 29.53059;
1240            ip = ip - Math.floor(ip);
1241            if(ip < 0.5)
1242            {
1243                ag = ip * 29.53059 + 29.53059 / 2;
1244            }
1245            else
1246            {
1247                ag = ip * 29.53059 - 29.53059 / 2;
1248            }
1249            this.phase = Math.floor(ag) + 1;            
1250        }
1251    }
1252    function updateElong(jday, obs) {
1253        // calculate elongation for object
1254        if (this.number == SUN) {
1255            return;
1256        }
1257        bodies[SUN].update(jday, obs);
1258        var ra2 = bodies[SUN].ra;
1259        var dec2 = bodies[SUN].dec;
1260        this.update(jday, obs);
1261        var dat = separation(this.ra, ra2, this.dec, dec2);
1262        this.elong = dat[0];
1263        this.pa = dat[1];
1264    }
1265    // heliocentric xyz for planet p
1266    // this is not from Meeus' book, but from Paul Schlyter
1267    // http://hem.passagen.se/pausch/comp/ppcomp.html
1268    // account for pertuberations of Jupiter, Saturn, Uranus (Uranus and Neptune
1269    // mutual pertubs are included in elements)
1270    // returns heliocentric x, y, z, distance, longitude and latitude of object
1271    function helios(p, jday) {
1272        var d = jday - 2451543.5;
1273        var w = p.w[0] + p.w[1] * d;
1274        // argument of perihelion
1275        var e = p.e[0] + p.e[1] * d;
1276        var a = p.a[0] + p.a[1] * d;
1277        var i = p.i[0] + p.i[1] * d;
1278        var N = p.N[0] + p.N[1] * d;
1279        var M = rev(p.M[0] + p.M[1] * d);
1280        // mean anomaly
1281        var E0 = M + RAD2DEG * e * sind(M) * (1.0 + e * cosd(M));
1282        var E1 = E0 - (E0 - RAD2DEG * e * sind(E0) - M) / (1.0 - e * cosd(E0));
1283        while (Math.abs(E0 - E1) > 0.0005) {
1284            E0 = E1;
1285            E1 = E0 - (E0 - RAD2DEG * e * sind(E0) - M) / (1.0 - e * cosd(E0));
1286        }
1287        var xv = a * (cosd(E1) - e);
1288        var yv = a * Math.sqrt(1.0 - e * e) * sind(E1);
1289        var v = rev(atan2d(yv, xv));
1290        // true anomaly
1291        var r = Math.sqrt(xv * xv + yv * yv);
1292        // distance
1293        var xh = r * (cosd(N) * cosd(v + w) - sind(N) * sind(v + w) * cosd(i));
1294        var yh = r * (sind(N) * cosd(v + w) + cosd(N) * sind(v + w) * cosd(i));
1295        var zh = r * (sind(v + w) * sind(i));
1296        var lonecl = atan2d(yh, xh);
1297        var latecl = atan2d(zh, Math.sqrt(xh * xh + yh * yh + zh * zh));
1298        if (p.num == JUPITER) {
1299            // Jupiter pertuberations by Saturn
1300            var Ms = rev(planets[SATURN].M[0] + planets[SATURN].M[1] * d);
1301            lonecl += (-0.332) * sind(2 * M - 5 * Ms - 67.6) - 0.056
1302                    * sind(2 * M - 2 * Ms + 21) + 0.042 * sind(3 * M - 5 * Ms + 21)
1303                    - 0.036 * sind(M - 2 * Ms) + 0.022 * cosd(M - Ms) + 0.023
1304                    * sind(2 * M - 3 * Ms + 52) - 0.016 * sind(M - 5 * Ms - 69);
1305            xh = r * cosd(lonecl) * cosd(latecl);
1306            // recalc xh, yh
1307            yh = r * sind(lonecl) * cosd(latecl);
1308        }
1309        if (p.num == SATURN) {
1310            // Saturn pertuberations
1311            var Mj = rev(planets[JUPITER].M[0] + planets[JUPITER].M[1] * d);
1312            lonecl += 0.812 * sind(2 * Mj - 5 * M - 67.6) - 0.229
1313                    * cosd(2 * Mj - 4 * M - 2) + 0.119 * sind(Mj - 2 * M - 3)
1314                    + 0.046 * sind(2 * Mj - 6 * M - 69) + 0.014
1315                    * sind(Mj - 3 * M + 32);
1316            latecl += -0.020 * cosd(2 * Mj - 4 * M - 2) + 0.018
1317                    * sind(2 * Mj - 6 * M - 49);
1318            xh = r * cosd(lonecl) * cosd(latecl);
1319            // recalc xh, yh, zh
1320            yh = r * sind(lonecl) * cosd(latecl);
1321            zh = r * sind(latecl);
1322        }
1323        if (p.num == URANUS) {
1324            // Uranus pertuberations
1325            var Mj = rev(planets[JUPITER].M[0] + planets[JUPITER].M[1] * d);
1326            var Ms = rev(planets[SATURN].M[0] + planets[SATURN].M[1] * d);
1327            lonecl += 0.040 * sind(Ms - 2 * M + 6) + 0.035 * sind(Ms - 3 * M + 33)
1328                    - 0.015 * sind(Mj - M + 20);
1329            xh = r * cosd(lonecl) * cosd(latecl);
1330            // recalc xh, yh
1331            yh = r * sind(lonecl) * cosd(latecl);
1332        }
1333        return new Array(xh, yh, zh, r, lonecl, latecl);
1334    }
1335    // helios()
1336    function radecr(obj, sun, jday, obs) {
1337        // radecr returns ra, dec and earth distance
1338        // obj and sun comprise Heliocentric Ecliptic Rectangular Coordinates
1339        // (note Sun coords are really Earth heliocentric coordinates with reverse
1340        // signs)
1341        // Equatorial geocentric co-ordinates
1342        var xg = obj[0] + sun[0];
1343        var yg = obj[1] + sun[1];
1344        var zg = obj[2];
1345        // Obliquity of Ecliptic (exponent corrected, was E-9!)
1346        var obl = 23.4393 - 3.563E-7 * (jday - 2451543.5);
1347        // Convert to eq. co-ordinates
1348        var x1 = xg;
1349        var y1 = yg * cosd(obl) - zg * sind(obl);
1350        var z1 = yg * sind(obl) + zg * cosd(obl);
1351        // RA and dec (33.2)
1352        var ra = rev(atan2d(y1, x1));
1353        var dec = atan2d(z1, Math.sqrt(x1 * x1 + y1 * y1));
1354        var dist = Math.sqrt(x1 * x1 + y1 * y1 + z1 * z1);
1355        return new Array(ra, dec, dist);
1356    }
1357    function radec2aa(ra, dec, jday, obs) {
1358        // Convert ra/dec to alt/az, also return hour angle, azimut = 0 when north
1359        // DOES NOT correct for parallax!
1360        // TH0=Greenwich sid. time (eq. 12.4), H=hour angle (chapter 13)
1361        var TH0 = 280.46061837 + 360.98564736629 * (jday - 2451545.0);
1362        var H = rev(TH0 - obs.longitude - ra);
1363        var alt = asind(sind(obs.latitude) * sind(dec) + cosd(obs.latitude)
1364                * cosd(dec) * cosd(H));
1365        var az = atan2d(sind(H), (cosd(H) * sind(obs.latitude) - tand(dec)
1366                * cosd(obs.latitude)));
1367        return new Array(alt, rev(az + 180.0), H);
1368    }
1369    function separation(ra1, ra2, dec1, dec2) {
1370        // ra, dec may also be long, lat, but PA is relative to the chosen
1371        // coordinate system
1372        var d = acosd(sind(dec1) * sind(dec2) + cosd(dec1) * cosd(dec2)
1373                * cosd(ra1 - ra2));
1374        // (Meeus 17.1)
1375        if (d < 0.1) {
1376            d = Math.sqrt(sqr(rev2(ra1 - ra2) * cosd((dec1 + dec2) / 2))
1377                    + sqr(dec1 - dec2));
1378        }
1379        // (17.2)
1380        var pa = atan2d(sind(ra1 - ra2), cosd(dec2) * tand(dec1) - sind(dec2)
1381                * cosd(ra1 - ra2));
1382        // angle
1383        return new Array(d, rev(pa));
1384    }
1385    // end separation()
1386    function PlanetAlt(p, jday, obs) {
1387        // Alt/Az, hour angle, ra/dec, ecliptic long. and lat, illuminated fraction,
1388        // dist(Sun), dist(Earth), brightness of planet p
1389        if (p == SUN) {
1390            return SunAlt(jday, obs);
1391        }
1392        if (p == MOON) {
1393            return MoonPos(jday, obs);
1394        }
1395        if (p == COMET) {
1396            return CometAlt(jday, obs);
1397        }
1398        var sun_xyz = sunxyz(jday);
1399        var planet_xyz = helios(planets[p], jday);
1400        var dx = planet_xyz[0] + sun_xyz[0];
1401        var dy = planet_xyz[1] + sun_xyz[1];
1402        var dz = planet_xyz[2] + sun_xyz[2];
1403        var lon = rev(atan2d(dy, dx));
1404        var lat = atan2d(dz, Math.sqrt(dx * dx + dy * dy));
1405        var radec = radecr(planet_xyz, sun_xyz, jday, obs);
1406        var ra = radec[0];
1407        var dec = radec[1];
1408        var altaz = radec2aa(ra, dec, jday, obs);
1409        var dist = radec[2];
1410        var R = sun_xyz[3];
1411        // Sun-Earth distance
1412        var r = planet_xyz[3];
1413        // heliocentric distance
1414        var k = ((r + dist) * (r + dist) - R * R) / (4 * r * dist);
1415        // illuminated fraction (41.2)
1416        // brightness calc according to Meeus p. 285-86 using Astronomical Almanac
1417        // expressions
1418        var absbr = new Array(-0.42, -4.40, 0, -1.52, -9.40, -8.88, -7.19, -6.87);
1419        var i = acosd((r * r + dist * dist - R * R) / (2 * r * dist));
1420        // phase angle
1421        var mag = absbr[p] + 5 * log10(r * dist);
1422        // common for all planets
1423        switch (p) {
1424        case MERCURY:
1425            mag += i * (0.0380 + i * (-0.000273 + i * 0.000002));
1426            break;
1427        case VENUS:
1428            mag += i * (0.0009 + i * (0.000239 - i * 0.00000065));
1429            break;
1430        case MARS:
1431            mag += i * 0.016;
1432            break;
1433        case JUPITER:
1434            mag += i * 0.005;
1435            break;
1436        case SATURN:
1437            // (Ring system needs special treatment, see Meeus Ch. 45)
1438            var T = (jday - 2451545.0) / 36525;
1439            // (22.1)
1440            var incl = 28.075216 - 0.012998 * T + 0.000004 * T * T;
1441            // (45.1)
1442            var omega = 169.508470 + 1.394681 * T + 0.000412 * T * T;
1443            // (45.1)
1444            var B = asind(sind(incl) * cosd(lat) * sind(lon - omega) - cosd(incl)
1445                    * sind(lat));
1446            var l = planet_xyz[4];
1447            // heliocentric longitude of Saturn
1448            var b = planet_xyz[5];
1449            // heliocentric latitude (do not confuse with 'b' in step 6, page 319)
1450            // correction for Sun's aberration skipped
1451            var U1 = atan2d(sind(incl) * sind(b) + cosd(incl) * cosd(b)
1452                    * sind(l - omega), cosd(b) * cosd(l - omega));
1453            var U2 = atan2d(sind(incl) * sind(lat) + cosd(incl) * cosd(lat)
1454                    * sind(lon - omega), cosd(lat) * cosd(lon - omega));
1455            var dU = Math.abs(U1 - U2);
1456            mag += 0.044 * dU - 2.60 * sind(Math.abs(B)) + 1.25 * sind(B) * sind(B);
1457            break;
1458        }
1459        return new Array(altaz[0], altaz[1], altaz[2], ra, dec, lon, lat, k, r,
1460                dist, mag, dx, dy, dz);
1461    }
1462
1463    
1464    return {
1465    
1466        update : function(julianDate, observer) {
1467            var obs = new observatory(atlas[0], 2012, 1, 1, 12, 0, 0);
1468            obs.latitude = observer.getLat();
1469            obs.longitude = observer.getLon();;
1470            
1471            for (i=0;i< bodies.length;i++) {
1472                
1473                if (bodies[i].name !== '') {
1474                    bodies[i].update(julianDate, obs);
1475                }
1476            }
1477            return bodies;
1478        },
1479        
1480        getPlanets : function() {
1481            return bodies;
1482        }
1483
1484    }
1485};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.