1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2017 Alexandru Csete, OZ9AEC.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, visit http://www.fsf.org/
18 */
19 #ifdef HAVE_CONFIG_H
20 #include <build-config.h>
21 #endif
22 #include <gtk/gtk.h>
23
24 #include "gtk-sat-data.h"
25 #include "locator.h"
26 #include "pass-to-txt.h"
27 #include "predict-tools.h"
28 #include "sat-cfg.h"
29 #include "sat-vis.h"
30 #include "sat-pass-dialogs.h"
31 #include "sgpsdp/sgp4sdp4.h"
32 #include "time-tools.h"
33
34
35 #define NUMCOL 19
36 #define COL_WIDTH 8
37
38
39 const gchar *SPCT[] = {
40 N_(" Time"),
41 N_(" Az "), /* 6 */
42 N_(" El "),
43 N_(" Ra "),
44 N_(" Dec "),
45 N_("Range"),
46 N_(" Rate "),
47 N_(" Lat "),
48 N_(" Lon "),
49 N_(" SSP "),
50 N_("Footp"),
51 N_(" Alt "),
52 N_(" Vel "),
53 N_(" Dop "),
54 N_(" Loss "),
55 N_(" Del "),
56 N_(" MA "),
57 N_(" Pha "),
58 N_("Vis")
59 };
60
61
62 const guint COLW[] = {
63 0,
64 6,
65 6,
66 6,
67 6,
68 5,
69 6,
70 6,
71 7,
72 6,
73 5,
74 5,
75 5,
76 5,
77 6,
78 5,
79 6,
80 6,
81 3
82 };
83
84
85 const gchar *MPCT[] = {
86 N_(" AOS"),
87 N_(" TCA"), /* 6 */
88 N_(" LOS"),
89 N_("Duration"),
90 N_("Max El"),
91 N_("AOS Az"),
92 N_("Max El Az"),
93 N_("LOS Az"),
94 N_("Orbit"),
95 N_("Vis")
96 };
97
98
99 const guint MCW[] = {
100 0,
101 0,
102 0,
103 8,
104 6,
105 6,
106 9,
107 6,
108 5,
109 3
110 };
111
112
113 static void Calc_RADec(gdouble jul_utc, gdouble saz, gdouble sel,
114 qth_t * qth, obs_astro_t * obs_set);
115
pass_to_txt_pgheader(pass_t * pass,qth_t * qth,gint fields)116 gchar *pass_to_txt_pgheader(pass_t * pass, qth_t * qth, gint fields)
117 {
118 gboolean loc;
119 gchar *utc;
120 gchar *header;
121 gchar aosbuff[TIME_FORMAT_MAX_LENGTH];
122 gchar losbuff[TIME_FORMAT_MAX_LENGTH];
123 gchar *fmtstr;
124 time_t aos, los;
125 guint size;
126
127 (void)fields; /* avoid unused parameter compiler warning */
128
129 fmtstr = sat_cfg_get_str(SAT_CFG_STR_TIME_FORMAT);
130 loc = sat_cfg_get_bool(SAT_CFG_BOOL_USE_LOCAL_TIME);
131 aos = (pass->aos - 2440587.5) * 86400.;
132 los = (pass->los - 2440587.5) * 86400.;
133
134 if (loc)
135 {
136 utc = g_strdup(_("Local"));
137
138 /* AOS */
139 size =
140 strftime(aosbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, localtime(&aos));
141 if (size == 0)
142 /* size > MAX_LENGTH */
143 aosbuff[TIME_FORMAT_MAX_LENGTH - 1] = '\0';
144
145 /* LOS */
146 size =
147 strftime(losbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, localtime(&los));
148 if (size == 0)
149 /* size > MAX_LENGTH */
150 losbuff[TIME_FORMAT_MAX_LENGTH - 1] = '\0';
151
152 }
153 else
154 {
155 utc = g_strdup(_("UTC"));
156
157 /* AOS */
158 size = strftime(aosbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, gmtime(&aos));
159 if (size == 0)
160 /* size > MAX_LENGTH */
161 aosbuff[TIME_FORMAT_MAX_LENGTH - 1] = '\0';
162
163 /* LOS */
164 size = strftime(losbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, gmtime(&los));
165 if (size == 0)
166 /* size > MAX_LENGTH */
167 losbuff[TIME_FORMAT_MAX_LENGTH - 1] = '\0';
168 }
169
170 header = g_strdup_printf(_("Pass details for %s (orbit %d)\n"
171 "Observer: %s, %s\n"
172 "LAT:%.2f LON:%.2f\n"
173 "AOS: %s %s\n"
174 "LOS: %s %s\n"),
175 pass->satname, pass->orbit,
176 qth->name, qth->loc, qth->lat, qth->lon,
177 aosbuff, utc, losbuff, utc);
178
179 g_free(utc);
180
181 return header;
182 }
183
pass_to_txt_tblheader(pass_t * pass,qth_t * qth,gint fields)184 gchar *pass_to_txt_tblheader(pass_t * pass, qth_t * qth, gint fields)
185 {
186 gchar *fmtstr;
187 guint size;
188 gchar tbuff[TIME_FORMAT_MAX_LENGTH];
189 guint i;
190 guint linelength = 0;
191 gchar *line;
192 gchar *sep;
193 gchar *buff;
194
195 (void)qth; /* avoid unused parameter compiler warning */
196
197 /* first, get the length of the time field */
198 fmtstr = sat_cfg_get_str(SAT_CFG_STR_TIME_FORMAT);
199 size = daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->aos);
200
201 g_free(fmtstr);
202
203 /* add time column */
204 buff = g_strnfill(size - 4, ' ');
205 line = g_strconcat(_(SPCT[0]), buff, NULL);
206 linelength = size + 1;
207 g_free(buff);
208
209 for (i = 1; i < NUMCOL; i++)
210 {
211
212 if (fields & (1 << i))
213 {
214
215 /* add column to line */
216 buff = g_strconcat(line, " ", _(SPCT[i]), NULL);
217 g_free(line);
218 line = g_strdup(buff);
219 g_free(buff);
220
221 /* update line length */
222 linelength += COLW[i] + 1;
223 }
224 }
225
226 /* add separator line */
227 sep = g_strnfill(linelength, '-');
228 buff = g_strdup_printf("%s\n%s\n%s\n", sep, line, sep);
229 g_free(line);
230 g_free(sep);
231
232 return buff;
233 }
234
pass_to_txt_tblcontents(pass_t * pass,qth_t * qth,gint fields)235 gchar *pass_to_txt_tblcontents(pass_t * pass, qth_t * qth,
236 gint fields)
237 {
238 gchar *fmtstr;
239 gchar tbuff[TIME_FORMAT_MAX_LENGTH];
240 guint i, num;
241 gchar *line;
242 gchar *data = NULL;
243 gchar *buff;
244 pass_detail_t *detail;
245 obs_astro_t astro;
246 gdouble ra, dec, numf;
247 gchar *ssp;
248
249 /* first, get the length of the time field */
250 fmtstr = sat_cfg_get_str(SAT_CFG_STR_TIME_FORMAT);
251 daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->aos);
252
253 /* get number of rows */
254 num = g_slist_length(pass->details);
255
256 for (i = 0; i < num; i++)
257 {
258
259 /* get detail */
260 detail = PASS_DETAIL(g_slist_nth_data(pass->details, i));
261
262 /* time */
263 daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, detail->time);
264
265 line = g_strdup_printf(" %s", tbuff);
266
267 /* Az */
268 if (fields & SINGLE_PASS_FLAG_AZ)
269 {
270 buff = g_strdup_printf("%s %6.2f", line, detail->az);
271 g_free(line);
272 line = g_strdup(buff);
273 g_free(buff);
274 }
275
276 /* El */
277 if (fields & SINGLE_PASS_FLAG_EL)
278 {
279 buff = g_strdup_printf("%s %6.2f", line, detail->el);
280 g_free(line);
281 line = g_strdup(buff);
282 g_free(buff);
283 }
284
285 /* Ra */
286 if (fields & SINGLE_PASS_FLAG_RA)
287 {
288 Calc_RADec(detail->time, detail->az, detail->el, qth, &astro);
289 ra = Degrees(astro.ra);
290 buff = g_strdup_printf("%s %6.2f", line, ra);
291 g_free(line);
292 line = g_strdup(buff);
293 g_free(buff);
294 }
295
296 /* Dec */
297 if (fields & SINGLE_PASS_FLAG_DEC)
298 {
299 Calc_RADec(detail->time, detail->az, detail->el, qth, &astro);
300 dec = Degrees(astro.dec);
301 buff = g_strdup_printf("%s %6.2f", line, dec);
302 g_free(line);
303 line = g_strdup(buff);
304 g_free(buff);
305 }
306
307 /* Range */
308 if (fields & SINGLE_PASS_FLAG_RANGE)
309 {
310 buff = g_strdup_printf("%s %5.0f", line, detail->range);
311 g_free(line);
312 line = g_strdup(buff);
313 g_free(buff);
314 }
315
316 /* Range Rate */
317 if (fields & SINGLE_PASS_FLAG_RANGE_RATE)
318 {
319 buff = g_strdup_printf("%s %6.3f", line, detail->range_rate);
320 g_free(line);
321 line = g_strdup(buff);
322 g_free(buff);
323 }
324
325 /* Lat */
326 if (fields & SINGLE_PASS_FLAG_LAT)
327 {
328 buff = g_strdup_printf("%s %6.2f", line, detail->lat);
329 g_free(line);
330 line = g_strdup(buff);
331 g_free(buff);
332 }
333
334 /* Lon */
335 if (fields & SINGLE_PASS_FLAG_LON)
336 {
337 buff = g_strdup_printf("%s %7.2f", line, detail->lon);
338 g_free(line);
339 line = g_strdup(buff);
340 g_free(buff);
341 }
342
343 /* SSP */
344 if (fields & SINGLE_PASS_FLAG_SSP)
345 {
346 ssp = g_try_malloc(7);
347 if (longlat2locator(detail->lon, detail->lat, ssp, 3) == RIG_OK)
348 {
349 buff = g_strdup_printf("%s %s", line, ssp);
350 g_free(line);
351 line = g_strdup(buff);
352 g_free(buff);
353 }
354 g_free(ssp);
355 }
356
357 /* Footprint */
358 if (fields & SINGLE_PASS_FLAG_FOOTPRINT)
359 {
360 buff = g_strdup_printf("%s %5.0f", line, detail->footprint);
361 g_free(line);
362 line = g_strdup(buff);
363 g_free(buff);
364 }
365
366 /* Alt */
367 if (fields & SINGLE_PASS_FLAG_ALT)
368 {
369 buff = g_strdup_printf("%s %5.0f", line, detail->alt);
370 g_free(line);
371 line = g_strdup(buff);
372 g_free(buff);
373 }
374
375 /* Vel */
376 if (fields & SINGLE_PASS_FLAG_VEL)
377 {
378 buff = g_strdup_printf("%s %5.3f", line, detail->velo);
379 g_free(line);
380 line = g_strdup(buff);
381 g_free(buff);
382 }
383
384 /* Doppler */
385 if (fields & SINGLE_PASS_FLAG_DOPPLER)
386 {
387 numf = -100.0e06 * (detail->range_rate / 299792.4580);
388 buff = g_strdup_printf("%s %5.0f", line, numf);
389 g_free(line);
390 line = g_strdup(buff);
391 g_free(buff);
392 }
393
394 /* Loss */
395 if (fields & SINGLE_PASS_FLAG_LOSS)
396 {
397 numf = 72.4 + 20.0 * log10(detail->range); // dB
398 buff = g_strdup_printf("%s %6.2f", line, numf);
399 g_free(line);
400 line = g_strdup(buff);
401 g_free(buff);
402 }
403
404 /* Delay */
405 if (fields & SINGLE_PASS_FLAG_DELAY)
406 {
407 numf = detail->range / 299.7924580; // msec
408 buff = g_strdup_printf("%s %5.2f", line, numf);
409 g_free(line);
410 line = g_strdup(buff);
411 g_free(buff);
412 }
413
414 /* MA */
415 if (fields & SINGLE_PASS_FLAG_MA)
416 {
417 buff = g_strdup_printf("%s %6.2f", line, detail->ma);
418 g_free(line);
419 line = g_strdup(buff);
420 g_free(buff);
421 }
422
423 /* Phase */
424 if (fields & SINGLE_PASS_FLAG_PHASE)
425 {
426 buff = g_strdup_printf("%s %6.2f", line, detail->phase);
427 g_free(line);
428 line = g_strdup(buff);
429 g_free(buff);
430 }
431
432 /* Visibility */
433 if (fields & SINGLE_PASS_FLAG_VIS)
434 {
435 buff = g_strdup_printf("%s %c", line, vis_to_chr(detail->vis));
436 g_free(line);
437 line = g_strdup(buff);
438 g_free(buff);
439 }
440
441 /* append line to return string */
442 if (i == 0)
443 {
444 data = g_strdup_printf("%s\n", line);
445 g_free(line);
446 }
447 else
448 {
449 buff = g_strconcat(data, line, "\n", NULL);
450 g_free(data);
451 data = g_strdup(buff);
452 g_free(buff);
453 }
454 }
455
456 g_free(fmtstr);
457
458 return data;
459 }
460
passes_to_txt_pgheader(GSList * passes,qth_t * qth,gint fields)461 gchar *passes_to_txt_pgheader(GSList * passes, qth_t * qth,
462 gint fields)
463 {
464 gchar *header;
465 pass_t *pass;
466
467 (void)fields;
468
469 pass = PASS(g_slist_nth_data(passes, 0));
470
471 header = g_strdup_printf(_("Upcoming passes for %s\n"
472 "Observer: %s, %s\n"
473 "LAT:%.2f LON:%.2f\n"),
474 pass->satname, qth->name, qth->loc,
475 qth->lat, qth->lon);
476
477 return header;
478 }
479
passes_to_txt_tblheader(GSList * passes,qth_t * qth,gint fields)480 gchar *passes_to_txt_tblheader(GSList * passes, qth_t * qth,
481 gint fields)
482 {
483 gchar *fmtstr;
484 guint size;
485 gchar tbuff[TIME_FORMAT_MAX_LENGTH];
486 guint i;
487 guint linelength = 0;
488 gchar *line;
489 gchar *sep;
490 gchar *buff;
491 pass_t *pass;
492
493 (void)qth;
494
495 /* first, get the length of the time field */
496 pass = PASS(g_slist_nth_data(passes, 0));
497 fmtstr = sat_cfg_get_str(SAT_CFG_STR_TIME_FORMAT);
498 size = daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->aos);
499
500 g_free(fmtstr);
501
502 /* add AOS, TCA, and LOS columns */
503 buff = g_strnfill(size - 3, ' ');
504 line =
505 g_strconcat(_(MPCT[0]), buff, _(MPCT[1]), buff, _(MPCT[2]), buff,
506 NULL);
507 linelength = 3 * (size + 2);
508 g_free(buff);
509
510 for (i = 3; i < 10; i++)
511 {
512 if (fields & (1 << i))
513 {
514
515 /* add column to line */
516 buff = g_strconcat(line, " ", _(MPCT[i]), NULL);
517 g_free(line);
518 line = g_strdup(buff);
519 g_free(buff);
520
521 /* update line length */
522 linelength += MCW[i] + 2;
523 }
524 }
525
526 /* add separator line */
527 sep = g_strnfill(linelength, '-');
528 buff = g_strdup_printf("%s\n%s\n%s\n", sep, line, sep);
529 g_free(line);
530 g_free(sep);
531
532 return buff;
533 }
534
passes_to_txt_tblcontents(GSList * passes,qth_t * qth,gint fields)535 gchar *passes_to_txt_tblcontents(GSList * passes, qth_t * qth,
536 gint fields)
537 {
538 gchar *fmtstr;
539 gchar tbuff[TIME_FORMAT_MAX_LENGTH];
540 guint i, num;
541 gchar *line = NULL;
542 gchar *data = NULL;
543 gchar *buff;
544 pass_t *pass;
545
546 (void)qth; /* avoid unused parameter compiler warning */
547
548 pass = PASS(g_slist_nth_data(passes, 0));
549
550 /* first, get the length of the time field */
551 fmtstr = sat_cfg_get_str(SAT_CFG_STR_TIME_FORMAT);
552 daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->aos);
553
554 /* get number of rows */
555 num = g_slist_length(passes);
556
557 for (i = 0; i < num; i++)
558 {
559
560 pass = PASS(g_slist_nth_data(passes, i));
561
562 /* AOS */
563 daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->aos);
564
565 line = g_strdup_printf(" %s", tbuff);
566
567 /* TCA */
568 daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->tca);
569
570 buff = g_strdup(line);
571 g_free(line);
572 line = g_strdup_printf("%s %s", buff, tbuff);
573 g_free(buff);
574
575 /* LOS */
576 daynum_to_str(tbuff, TIME_FORMAT_MAX_LENGTH, fmtstr, pass->los);
577
578 buff = g_strdup(line);
579 g_free(line);
580 line = g_strdup_printf("%s %s", buff, tbuff);
581 g_free(buff);
582
583 /* Duration */
584 if (fields & (1 << MULTI_PASS_COL_DURATION))
585 {
586 guint h, m, s;
587
588 /* convert julian date to seconds */
589 s = (guint) ((pass->los - pass->aos) * 86400);
590
591 /* extract hours */
592 h = (guint) floor(s / 3600);
593 s -= 3600 * h;
594
595 /* extract minutes */
596 m = (guint) floor(s / 60);
597 s -= 60 * m;
598
599 buff = g_strdup_printf("%s %02d:%02d:%02d", line, h, m, s);
600 g_free(line);
601 line = g_strdup(buff);
602 g_free(buff);
603 }
604
605 /* Max El */
606 if (fields & (1 << MULTI_PASS_COL_MAX_EL))
607 {
608 buff = g_strdup_printf("%s %6.2f", line, pass->max_el);
609 g_free(line);
610 line = g_strdup(buff);
611 g_free(buff);
612 }
613
614 /* AOS Az */
615 if (fields & (1 << MULTI_PASS_COL_AOS_AZ))
616 {
617 buff = g_strdup_printf("%s %6.2f", line, pass->aos_az);
618 g_free(line);
619 line = g_strdup(buff);
620 g_free(buff);
621 }
622
623 /* Max El Az */
624 if (fields & (1 << MULTI_PASS_COL_MAX_EL_AZ))
625 {
626 buff = g_strdup_printf("%s %9.2f", line, pass->maxel_az);
627 g_free(line);
628 line = g_strdup(buff);
629 g_free(buff);
630 }
631
632 /* LOS Az */
633 if (fields & (1 << MULTI_PASS_COL_LOS_AZ))
634 {
635 buff = g_strdup_printf("%s %6.2f", line, pass->los_az);
636 g_free(line);
637 line = g_strdup(buff);
638 g_free(buff);
639 }
640
641 /* Orbit */
642 if (fields & (1 << MULTI_PASS_COL_ORBIT))
643 {
644 buff = g_strdup_printf("%s %5d", line, pass->orbit);
645 g_free(line);
646 line = g_strdup(buff);
647 g_free(buff);
648 }
649
650 /* Visibility */
651 if (fields & (1 << MULTI_PASS_COL_VIS))
652 {
653 buff = g_strdup_printf("%s %s", line, pass->vis);
654 g_free(line);
655 line = g_strdup(buff);
656 g_free(buff);
657 }
658
659 /* append line to return string */
660 if (i == 0)
661 {
662 data = g_strdup_printf("%s\n", line);
663 g_free(line);
664 }
665 else
666 {
667 buff = g_strconcat(data, line, "\n", NULL);
668 g_free(data);
669 data = g_strdup(buff);
670 g_free(buff);
671 }
672
673 }
674
675 g_free(fmtstr);
676
677 return data;
678 }
679
Calc_RADec(gdouble jul_utc,gdouble saz,gdouble sel,qth_t * qth,obs_astro_t * obs_set)680 static void Calc_RADec(gdouble jul_utc, gdouble saz, gdouble sel,
681 qth_t * qth, obs_astro_t * obs_set)
682 {
683 double phi, theta, sin_theta, cos_theta, sin_phi, cos_phi,
684 az, el, Lxh, Lyh, Lzh, Sx, Ex, Zx, Sy, Ey, Zy, Sz, Ez, Zz,
685 Lx, Ly, Lz, cos_delta, sin_alpha, cos_alpha;
686 geodetic_t geodetic;
687
688
689 geodetic.lon = qth->lon * de2ra;
690 geodetic.lat = qth->lat * de2ra;
691 geodetic.alt = qth->alt / 1000.0;
692 geodetic.theta = 0;
693
694 az = saz * de2ra;
695 el = sel * de2ra;
696 phi = geodetic.lat;
697 theta = FMod2p(ThetaG_JD(jul_utc) + geodetic.lon);
698 sin_theta = sin(theta);
699 cos_theta = cos(theta);
700 sin_phi = sin(phi);
701 cos_phi = cos(phi);
702 Lxh = -cos(az) * cos(el);
703 Lyh = sin(az) * cos(el);
704 Lzh = sin(el);
705 Sx = sin_phi * cos_theta;
706 Ex = -sin_theta;
707 Zx = cos_theta * cos_phi;
708 Sy = sin_phi * sin_theta;
709 Ey = cos_theta;
710 Zy = sin_theta * cos_phi;
711 Sz = -cos_phi;
712 Ez = 0;
713 Zz = sin_phi;
714 Lx = Sx * Lxh + Ex * Lyh + Zx * Lzh;
715 Ly = Sy * Lxh + Ey * Lyh + Zy * Lzh;
716 Lz = Sz * Lxh + Ez * Lyh + Zz * Lzh;
717 obs_set->dec = ArcSin(Lz); /* Declination (radians) */
718 cos_delta = sqrt(1 - Sqr(Lz));
719 sin_alpha = Ly / cos_delta;
720 cos_alpha = Lx / cos_delta;
721 obs_set->ra = AcTan(sin_alpha, cos_alpha); /* Right Ascension (radians) */
722 obs_set->ra = FMod2p(obs_set->ra);
723 }
724