1 /* wmjupiter - Copyright (c) 2001 Thomas Kuiper <tkuiper@inxsoft.net> */
2 
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <ctype.h>
8 #include <time.h>
9 #include <X11/X.h>
10 #include <X11/xpm.h>
11 #include <math.h>
12 #include <float.h>
13 #include "xutils.h"
14 #include "wmJupiter_master.xpm"
15 #include "wmJupiter_mask.xbm"
16 
17 typedef struct Coordinates {
18     double x;
19     double y;
20 } Coordinates;
21 
22 #define PI 3.141592653589793238462643383279502884197169399375105
23 
24 double lambda, lambda1, lambda2;
25 double jdistance;
26 int spotlat;
27 
28 double De;			// planetocentric ang. dist. of earth from jup. equator
29 // Angles of each of the Galilean satellites, in radians,
30 // expressed relative to each satellite's inferior conjunction:
31 double moonAngles[5];
32 // And their distances from the planet:
33 double moonDist[5];
34 char moonLabels[5];
35 
36 /* compute the julian date between 1901 - 2099 (Sinnott 1991, p. 183) */
37 
getJulianDate(double year,double month,double day,double uh,double um,double us)38 double getJulianDate(double year, double month, double day,
39 		     double uh, double um, double us)
40 {
41     return 367 * year - (int) (7 * (year + (int) ((month + 9) / 12)) / 4)
42 	+ (int) (275 * month / 9) + day + 1721013.5
43 	+ (uh + (um + us / 60.0) / 60.0) / 24.0;
44 
45 }
46 
oangle(double a)47 double oangle(double a)
48 {
49     while (a > 2 * PI)
50 	a -= 2. * PI;
51     while (a < 0)
52 	a += 2. * PI;
53     return a;
54 }
55 
56 
angle(double a)57 double angle(double a)
58 {
59     if (a < 10000)
60 	return oangle(a);
61     a = a - 2. * PI * (int) (a / 2. / PI);
62     if (a < 0)
63 	a += 2 * PI;
64     return a;
65 }
66 
getRedSpotXY(int spot_in_deg)67 Coordinates getRedSpotXY(int spot_in_deg)
68 {
69     double spotlong = angle(lambda2 - spot_in_deg * PI / 180);
70     Coordinates coord;
71 
72 
73     // See if the spot is visible:
74     if (spotlong > PI * .5 && spotlong < PI * 1.5) {
75 	coord.x = coord.y = DBL_MAX;
76     } else {
77 	coord.x = sin(spotlong);
78 	coord.y = .42;		// completely random wild-assed guess
79 
80     }
81 
82 
83     return coord;
84 }
85 
86 struct tm *tmjupiter = NULL;
87 void computepos(double d);
findspot()88 void findspot()
89 {
90     time_t t;
91     double d;
92 
93     t = time(0);
94 
95     tmjupiter = gmtime(&t);
96 
97 
98     d = getJulianDate(tmjupiter->tm_year + 1900, tmjupiter->tm_mon + 1,
99 		      tmjupiter->tm_mday, tmjupiter->tm_hour,
100 		      tmjupiter->tm_min, tmjupiter->tm_sec) - 2415020;
101     computepos(d);
102 
103 }
104 
drawspot()105 void drawspot()
106 {
107     int jsize;
108     int xcenter;
109     int ycenter;
110     int x, y, j2width, spotwidth;
111     Coordinates coord;
112     int redSpotWidth, redSpotHeight;
113     redSpotWidth = 3;
114     redSpotHeight = 4;
115     xcenter = 26;
116     jsize = 10;
117     ycenter = 32;
118 
119     if (tmjupiter == NULL)
120 	return;
121 
122     coord = getRedSpotXY(spotlat);
123 
124     if (coord.y == DBL_MAX) {
125     } else {
126 
127     }
128 
129     if (coord.x != DBL_MAX && coord.y != DBL_MAX) {
130 	// We only want the spot to draw to the edge of the disk,
131 	// so adjust the width if necessary:
132 	// (approx) width/2 of the planet (pixels) at the spot's latitude:
133 	j2width = (int) (jsize - abs(coord.y * jsize) / 3);
134 	x = xcenter + (int) (coord.x * jsize);
135 	y = ycenter + (int) (coord.y * jsize) - redSpotHeight / 2;
136 	spotwidth = redSpotWidth;
137 	if (x + redSpotWidth > xcenter + j2width) {
138 	    spotwidth = xcenter + j2width - x;
139 	    x = xcenter + j2width - spotwidth;
140 	} else if (x - redSpotWidth / 2 < xcenter - j2width) {
141 	    spotwidth = x + redSpotWidth / 2 - xcenter + j2width;
142 	    x = xcenter - j2width;
143 	} else {
144 	    x -= redSpotWidth / 2;
145 	}
146 
147 	copyXPMArea(73, 88, 4, 3, x + 2, 28);
148 
149     }
150 
151 }
152 
153 
getMoonDist(int whichmoon)154 double getMoonDist(int whichmoon)
155 {
156     return moonDist[whichmoon];
157 }
158 
drawmoons()159 void drawmoons()
160 {
161     Coordinates coord;
162     int i;
163     char chr;
164     double r;
165     int moonsize = 5;
166 
167     for (i = 0; i < 4; i++) {
168 	r = getMoonDist(i);
169 	coord.x = r * sin(moonAngles[i]);
170 	coord.y = -r * cos(moonAngles[i]) * sin(De);
171 
172 	if (coord.x < 1. && coord.x > -1.
173 	    && moonAngles[i] > PI * .5 && moonAngles[i] < PI * 1.5) {
174 	    coord.x = coord.y = DBL_MAX;
175 	}
176 
177 	if ((coord.x != DBL_MAX)
178 	    && (coord.y != DBL_MAX)) {
179 	    int x = 32 + (int) (coord.x * 10) - moonsize / 2;
180 	    int y = 32 - (int) (coord.y * 10) - moonsize / 2;
181 	    if ((x > 2) && (x < 55) && (y > 2) && (y < 60)) {
182 		copyXPMArea(78, 88, 4, 4, x, y);
183 		chr = moonLabels[i] - 65;
184 		copyXPMArea(chr * 5 + 2, 128, 5, 6, x, 6);
185 	    }
186 	}
187     }
188 }
189 
190 
computepos(double d)191 void computepos(double d)
192 {
193 
194 
195     double psi;
196     double delta;		/* Earth-Jupiter distance */
197     double V, M, N, J, A, B, K, R, r, G, H;
198 
199     // Argument for the long-period term in the motion of Jupiter:
200     V = angle((134.63 + .00111587 * d) * PI / 180);
201 
202     // Mean anomalies of Earth and Jupiter:
203     M = angle((358.476 + .9856003 * d) * PI / 180);
204     N = angle((225.328 + .0830853 * d + .33 * sin(V))
205 	      * PI / 180);
206 
207     // Diff between the mean heliocentric longitudes of Earth & Jupiter:
208     J = angle((221.647 + .9025179 * d - .33 * sin(V))
209 	      * PI / 180);
210 
211     // Equations of the center of Earth and Jupiter:
212     A = angle((1.916 * sin(M) + .020 * sin(2 * M))
213 	      * PI / 180);
214     B = angle((5.552 * sin(N) + .167 * sin(2 * N))
215 	      * PI / 180);
216 
217     K = angle(J + A - B);
218 
219     // Distances are specified in AU:
220     // Radius vector of the earth:
221     R = 1.00014 - .01672 * cos(M) - .00014 * cos(2 * M);
222     // Radius vector of Jupiter:
223     r = 5.20867 - .25192 * cos(N) - .00610 * cos(2 * N);
224 
225     // Earth-Jupiter distance:
226     delta = sqrt(r * r + R * R - 2 * r * R * cos(K));
227     jdistance = delta;
228 
229     // Phase angle of Jupiter (always btw. -12 and 12 degrees):
230     psi = asin(R / delta * sin(K));
231 
232     // Longitude of system 1:
233     lambda1 = angle((268.28 * 877.8169088 * (d - delta / 173))
234 		    * PI / 180 + psi - B);
235     // Longitude of system 2:
236     lambda2 = angle((290.28 + 870.1869088 * (d - delta / 173))
237 		    * PI / 180 + psi - B);
238 
239     // calculate the angles of each of the satellites:
240     moonAngles[0] = angle((84.5506 + 203.4058630 * (d - delta / 173))
241 			  * PI / 180 + psi - B);
242     moonAngles[1] = angle((41.5015 + 101.2916323 * (d - delta / 173))
243 			  * PI / 180 + psi - B);
244     moonAngles[2] = angle((109.9770 + 50.2345169 * (d - delta / 173))
245 			  * PI / 180 + psi - B);
246     moonAngles[3] = oangle((176.3586 + 21.4879802 * (d - delta / 173))
247 			   * PI / 180 + psi - B);
248 
249     // and the planetocentric angular distance of the earth
250     // from the equator of Jupiter:
251     lambda = angle((238.05 + .083091 * d + .33 * sin(V))
252 		   * PI / 180 + B);
253     De = ((3.07 * sin(lambda + 44.5 * PI / 180)
254 	   - 2.15 * sin(psi) * cos(lambda - 24. * PI / 180)
255 	   - 1.31 * (r - delta) / delta * sin(lambda - 99.4 * PI / 180))
256 	  * PI / 180);
257 
258     G = angle((187.3 + 50.310674 * (d - delta / 173)) * PI / 180);
259     H = angle((311.1 + 21.569229 * (d - delta / 173)) * PI / 180);
260 
261     // Calculate the distances before any corrections are applied:
262     moonDist[0] = 5.9061 -
263 	.0244 * cos(2 * (moonAngles[0] - moonAngles[1]));
264     moonDist[1] = 9.3972 -
265 	.0889 * cos(2 * (moonAngles[1] - moonAngles[2]));
266     moonDist[2] = 14.9894 - .0227 * cos(G);
267     moonDist[3] = 26.3649 - .1944 * cos(H);
268 
269     // apply some first-order correction terms to the angles:
270     moonAngles[0] = angle(moonAngles[0] +
271 			  sin(2 * (moonAngles[0] - moonAngles[1]))
272 			  * .472 * PI / 180);
273     moonAngles[1] = angle(moonAngles[1] +
274 			  sin(2 * (moonAngles[1] - moonAngles[2]))
275 			  * 1.073 * PI / 180);
276     moonAngles[2] = angle(moonAngles[2] + sin(G) * .174 * PI / 180);
277     moonAngles[3] = angle(moonAngles[3] + sin(H) * .845 * PI / 180);
278 
279 }
280 
281 /*
282  *  Delay between refreshes (in microseconds)
283  */
284 #define DELAY 10000L
285 #define DEFAULT_UPDATEDELAY 900L
286 
287 void ButtonPressEvent(XButtonEvent *);
288 void KeyPressEvent(XKeyEvent *);
289 char *StringToUpper(char *);
290 
291 
292 int UpToDate = 0;
293 long UpdateDelay;
294 int GotFirstClick1, GotDoubleClick1;
295 int GotFirstClick2, GotDoubleClick2;
296 int GotFirstClick3, GotDoubleClick3;
297 int DblClkDelay;
298 
299 
300 char LabelColor[30] = "#79bdbf";
301 char WindGustColor[30] = "#ff0000";
302 char DataColor[30] = "#ffbf50";
303 char BackColor[30] = "#181818";
304 char StationTimeColor[30] = "#c5a6ff";
305 
306 
307 
main(int argc,char * argv[])308 int main(int argc, char *argv[])
309 {
310 
311     XEvent event;
312     int m, dt1, dt2, dt3;
313     Window myWindow;
314     char tempstr[255];
315     int q, i;
316     double val;
317     int digit;
318     m = 101;
319     initXwindow(argc, argv);
320     myWindow =
321 	openXwindow(argc, argv, wmJupiter_master, wmJupiter_mask_bits,
322 		    wmJupiter_mask_width, wmJupiter_mask_height, BackColor,
323 		    LabelColor, WindGustColor, DataColor,
324 		    StationTimeColor);
325 
326     if (argc < 2) {
327 	printf
328 	    ("usage: wmJupiter <spot position>\n  spot position in lat. (e.g. 80)\n");
329 	return 1;
330     }
331 
332     spotlat = atoi(argv[1]);
333 
334     moonLabels[0] = 'I';
335     moonLabels[1] = 'E';
336     moonLabels[2] = 'G';
337     moonLabels[3] = 'C';
338 
339     findspot();
340 
341     DblClkDelay = 32000;
342     UpToDate = 0;
343     while (1) {
344 
345 	if (DblClkDelay > 15) {
346 
347 	    DblClkDelay = 0;
348 	    GotFirstClick1 = 0;
349 	    GotDoubleClick1 = 0;
350 	    GotFirstClick2 = 0;
351 	    GotDoubleClick2 = 0;
352 	    GotFirstClick3 = 0;
353 	    GotDoubleClick3 = 0;
354 
355 	} else {
356 
357 	    ++DblClkDelay;
358 
359 	}
360 
361 
362 	/*
363 	 *   Process any pending X events.
364 	 */
365 	while (XPending(display)) {
366 	    XNextEvent(display, &event);
367 	    switch (event.type) {
368 	    case Expose:
369 		RedrawWindow();
370 		break;
371 	    case ButtonPress:
372 		ButtonPressEvent(&event.xbutton);
373 		break;
374 	    case KeyPress:
375 		KeyPressEvent(&event.xkey);
376 		break;
377 	    case ButtonRelease:
378 		break;
379 	    case EnterNotify:
380 		XSetInputFocus(display, PointerRoot, RevertToParent,
381 			       CurrentTime);
382 		break;
383 	    case LeaveNotify:
384 		XSetInputFocus(display, PointerRoot, RevertToParent,
385 			       CurrentTime);
386 		break;
387 
388 	    }
389 	}
390 
391 	q = 0;
392 /*	    copyXPMArea(5, 69, 54, 54, 5, 5);
393 	    chr = 'A' - 65;
394 			 copyXPMArea(chr*5+2, 128, 5, 6, 7+q, 6); q+= 5;
395 	    chr = 'B' - 65;
396 			 copyXPMArea(chr*5+2, 128, 5, 6, 7+q, 6); q+= 5;
397 */
398 	copyXPMArea(5, 69, 54, 54, 4, 4);
399 
400 	drawspot();
401 	copyXPMArea(82, 90, 7, 18, 14, 15);
402 	copyXPMArea(82, 90, 7, 18, 41, 15);
403 	drawmoons();
404 
405 	sprintf(tempstr, "%2.5f", jdistance);
406 
407 
408 	q = 0;
409 	val = jdistance;
410 	for (i = 0; i < 7; i++) {
411 	    if (tempstr[i] == '\0')
412 		break;
413 	    digit = tempstr[i] - 48;
414 	    if (digit >= 0) {
415 		copyXPMArea(digit * 5 + 66, 57, 5, 6, 22 + q, 50);
416 		q += 5;
417 	    } else {
418 		copyXPMArea(10 * 5 + 66, 57, 5, 6, 22 + q, 50);
419 		q += 5;
420 	    }
421 	}
422 
423 	if (m > 100) {
424 
425 	    findspot();
426 	    m = 0;
427 	    ++dt1;
428 	    ++dt2;
429 	    ++dt3;
430 
431 
432 	} else {
433 
434 	    /*
435 	     *  Increment counter
436 	     */
437 	    ++m;
438 
439 	}
440 
441 	RedrawWindow();
442 
443 	usleep(DELAY);
444     }
445 }
446 
447 
448 
449 
ButtonPressEvent(XButtonEvent * xev)450 void ButtonPressEvent(XButtonEvent * xev)
451 {
452 
453     /*
454      *  Process single clicks.
455      */
456     DblClkDelay = 0;
457     if ((xev->button == Button1) && (xev->type == ButtonPress)) {
458 
459 	if (GotFirstClick1)
460 	    GotDoubleClick1 = 1;
461 	else
462 	    GotFirstClick1 = 1;
463 
464     } else if ((xev->button == Button2) && (xev->type == ButtonPress)) {
465 
466 	if (GotFirstClick2)
467 	    GotDoubleClick2 = 1;
468 	else
469 	    GotFirstClick2 = 1;
470 
471     } else if ((xev->button == Button3) && (xev->type == ButtonPress)) {
472 
473 	if (GotFirstClick3)
474 	    GotDoubleClick3 = 1;
475 	else
476 	    GotFirstClick3 = 1;
477 
478     }
479 
480 
481 
482 
483     /*
484      *  We got a double click on Mouse Button1 (i.e. the left one)
485      */
486     if (GotDoubleClick1) {
487 	GotFirstClick1 = 0;
488 	GotDoubleClick1 = 0;
489     }
490 
491 
492     /*
493      *  We got a double click on Mouse Button2 (i.e. the left one)
494      */
495     if (GotDoubleClick2) {
496 	GotFirstClick2 = 0;
497 	GotDoubleClick2 = 0;
498     }
499 
500 
501     /*
502      *  We got a double click on Mouse Button3 (i.e. the left one)
503      */
504     if (GotDoubleClick3) {
505 	GotFirstClick3 = 0;
506 	GotDoubleClick3 = 0;
507     }
508 
509     return;
510 
511 
512 }
513 
514 
515 
516 
517 /*
518  *  This routine handles key presses.
519  *
520  */
KeyPressEvent(XKeyEvent * xev)521 void KeyPressEvent(XKeyEvent * xev)
522 {
523 
524     return;
525 
526 }
527 
528 
StringToUpper(char * String)529 char *StringToUpper(char *String)
530 {
531 
532     int i;
533 
534     for (i = 0; i < strlen(String); i++)
535 	String[i] = toupper(String[i]);
536 
537     return String;
538 
539 }
540