1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2017 Alexandru Csete, OZ9AEC.
5 Copyright (C) 2006-2007 William J Beksi, KC2EXL.
6 Copyright (C) 2013 Charles Suprin, AA1VS.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, visit http://www.fsf.org/
20 */
21 #ifdef HAVE_CONFIG_H
22 #include <build-config.h>
23 #endif
24
25 #include <goocanvas.h>
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 #include <math.h>
29 #include <string.h>
30
31 #include "compat.h"
32 #include "config-keys.h"
33 #include "gpredict-utils.h"
34 #include "gtk-sat-data.h"
35 #include "gtk-sat-map-popup.h"
36 #include "gtk-sat-map-ground-track.h"
37 #include "gtk-sat-map.h"
38 #include "locator.h"
39 #include "map-tools.h"
40 #include "mod-cfg-get-param.h"
41 #include "orbit-tools.h"
42 #include "predict-tools.h"
43 #include "sat-cfg.h"
44 #include "sat-info.h"
45 #include "sat-log.h"
46 #include "sgpsdp/sgp4sdp4.h"
47 #include "time-tools.h"
48
49 #define MARKER_SIZE_HALF 1
50
51 /* Update terminator every 30 seconds */
52 #define TERMINATOR_UPDATE_INTERVAL (15.0/86400.0)
53
54 static void gtk_sat_map_class_init(GtkSatMapClass * class);
55 static void gtk_sat_map_init(GtkSatMap * polview);
56 static void gtk_sat_map_destroy(GtkWidget * widget);
57 static void size_allocate_cb(GtkWidget * widget,
58 GtkAllocation * allocation, gpointer data);
59 static void update_map_size(GtkSatMap * satmap);
60 static void update_sat(gpointer key, gpointer value, gpointer data);
61 static void plot_sat(gpointer key, gpointer value, gpointer data);
62 static void lonlat_to_xy(GtkSatMap * m, gdouble lon, gdouble lat,
63 gfloat * x, gfloat * y);
64 static void xy_to_lonlat(GtkSatMap * m, gfloat x, gfloat y, gfloat * lon,
65 gfloat * lat);
66 static gboolean on_motion_notify(GooCanvasItem * item, GooCanvasItem * target,
67 GdkEventMotion * event, gpointer data);
68 static void on_item_created(GooCanvas * canvas, GooCanvasItem * item,
69 GooCanvasItemModel * model, gpointer data);
70 static void on_canvas_realized(GtkWidget * canvas, gpointer data);
71 static gboolean on_button_press(GooCanvasItem * item,
72 GooCanvasItem * target,
73 GdkEventButton * event, gpointer data);
74 static gboolean on_button_release(GooCanvasItem * item,
75 GooCanvasItem * target,
76 GdkEventButton * event, gpointer data);
77 static void clear_selection(gpointer key, gpointer val, gpointer data);
78 static void load_map_file(GtkSatMap * satmap, float clon);
79 static GooCanvasItemModel *create_canvas_model(GtkSatMap * satmap);
80 static gdouble arccos(gdouble, gdouble);
81 static gboolean pole_is_covered(sat_t * sat);
82 static gboolean north_pole_is_covered(sat_t * sat);
83 static gboolean south_pole_is_covered(sat_t * sat);
84 static gboolean mirror_lon(sat_t * sat, gdouble rangelon, gdouble * mlon,
85 gdouble mapbreak);
86 static guint calculate_footprint(GtkSatMap * satmap, sat_t * sat);
87 static void split_points(GtkSatMap * satmap, sat_t * sat, gdouble sspx);
88 static void sort_points_x(GtkSatMap * satmap, sat_t * sat,
89 GooCanvasPoints * points, gint num);
90 static void sort_points_y(GtkSatMap * satmap, sat_t * sat,
91 GooCanvasPoints * points, gint num);
92 static gint compare_coordinates_x(gconstpointer a, gconstpointer b,
93 gpointer data);
94 static gint compare_coordinates_y(gconstpointer a, gconstpointer b,
95 gpointer data);
96 static void update_selected(GtkSatMap * satmap, sat_t * sat);
97 static void draw_grid_lines(GtkSatMap * satmap, GooCanvasItemModel * root);
98 static void redraw_grid_lines(GtkSatMap * satmap);
99 static void draw_terminator(GtkSatMap * satmap, GooCanvasItemModel * root);
100 static void redraw_terminator(GtkSatMap * satmap);
101 static gchar *aoslos_time_to_str(GtkSatMap * satmap, sat_t * sat);
102 static void gtk_sat_map_load_showtracks(GtkSatMap * map);
103 static void gtk_sat_map_store_showtracks(GtkSatMap * satmap);
104 static void gtk_sat_map_load_hide_coverages(GtkSatMap * map);
105 static void gtk_sat_map_store_hidecovs(GtkSatMap * satmap);
106 static void reset_ground_track(gpointer key, gpointer value,
107 gpointer user_data);
108
109 static GtkVBoxClass *parent_class = NULL;
110 static GooCanvasPoints *points1;
111 static GooCanvasPoints *points2;
112
113
gtk_sat_map_get_type()114 GType gtk_sat_map_get_type()
115 {
116 static GType gtk_sat_map_type = 0;
117
118 if (!gtk_sat_map_type)
119 {
120 static const GTypeInfo gtk_sat_map_info = {
121 sizeof(GtkSatMapClass),
122 NULL, /* base init */
123 NULL, /* base finalize */
124 (GClassInitFunc) gtk_sat_map_class_init,
125 NULL, /* class finalize */
126 NULL, /* class data */
127 sizeof(GtkSatMap),
128 5, /* n_preallocs */
129 (GInstanceInitFunc) gtk_sat_map_init,
130 NULL
131 };
132
133 gtk_sat_map_type = g_type_register_static(GTK_TYPE_BOX,
134 "GtkSatMap",
135 >k_sat_map_info, 0);
136 }
137
138 return gtk_sat_map_type;
139 }
140
gtk_sat_map_class_init(GtkSatMapClass * class)141 static void gtk_sat_map_class_init(GtkSatMapClass * class)
142 {
143 GtkWidgetClass *widget_class;
144
145 widget_class = (GtkWidgetClass *) class;
146 widget_class->destroy = gtk_sat_map_destroy;
147 parent_class = g_type_class_peek_parent(class);
148 }
149
gtk_sat_map_init(GtkSatMap * satmap)150 static void gtk_sat_map_init(GtkSatMap * satmap)
151 {
152 satmap->sats = NULL;
153 satmap->qth = NULL;
154 satmap->obj = NULL;
155 satmap->showtracks = g_hash_table_new_full(g_int_hash, g_int_equal,
156 NULL, NULL);
157 satmap->hidecovs = g_hash_table_new_full(g_int_hash, g_int_equal,
158 NULL, NULL);
159 satmap->naos = 0.0;
160 satmap->ncat = 0;
161 satmap->tstamp = 2458849.5;
162 satmap->x0 = 0;
163 satmap->y0 = 0;
164 satmap->width = 0;
165 satmap->height = 0;
166 satmap->refresh = 0;
167 satmap->counter = 0;
168 satmap->show_terminator = FALSE;
169 satmap->qthinfo = FALSE;
170 satmap->eventinfo = FALSE;
171 satmap->cursinfo = FALSE;
172 satmap->showgrid = FALSE;
173 satmap->keepratio = FALSE;
174 satmap->resize = FALSE;
175 }
176
gtk_sat_map_destroy(GtkWidget * widget)177 static void gtk_sat_map_destroy(GtkWidget * widget)
178 {
179 gtk_sat_map_store_showtracks(GTK_SAT_MAP(widget));
180 gtk_sat_map_store_hidecovs(GTK_SAT_MAP(widget));
181 (*GTK_WIDGET_CLASS(parent_class)->destroy) (widget);
182 }
183
gtk_sat_map_new(GKeyFile * cfgdata,GHashTable * sats,qth_t * qth)184 GtkWidget *gtk_sat_map_new(GKeyFile * cfgdata, GHashTable * sats,
185 qth_t * qth)
186 {
187 GtkSatMap *satmap;
188 GooCanvasItemModel *root;
189 guint32 col;
190
191 satmap = g_object_new(GTK_TYPE_SAT_MAP, NULL);
192
193 satmap->cfgdata = cfgdata;
194 satmap->sats = sats;
195 satmap->qth = qth;
196
197 satmap->obj = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
198
199 satmap->refresh = mod_cfg_get_int(cfgdata,
200 MOD_CFG_MAP_SECTION,
201 MOD_CFG_MAP_REFRESH,
202 SAT_CFG_INT_MAP_REFRESH);
203 satmap->counter = 1;
204
205 satmap->qthinfo = mod_cfg_get_bool(cfgdata,
206 MOD_CFG_MAP_SECTION,
207 MOD_CFG_MAP_SHOW_QTH_INFO,
208 SAT_CFG_BOOL_MAP_SHOW_QTH_INFO);
209
210 satmap->eventinfo = mod_cfg_get_bool(cfgdata,
211 MOD_CFG_MAP_SECTION,
212 MOD_CFG_MAP_SHOW_NEXT_EVENT,
213 SAT_CFG_BOOL_MAP_SHOW_NEXT_EV);
214
215 satmap->cursinfo = mod_cfg_get_bool(cfgdata,
216 MOD_CFG_MAP_SECTION,
217 MOD_CFG_MAP_SHOW_CURS_TRACK,
218 SAT_CFG_BOOL_MAP_SHOW_CURS_TRACK);
219
220 satmap->showgrid = mod_cfg_get_bool(cfgdata,
221 MOD_CFG_MAP_SECTION,
222 MOD_CFG_MAP_SHOW_GRID,
223 SAT_CFG_BOOL_MAP_SHOW_GRID);
224
225 satmap->keepratio = mod_cfg_get_bool(cfgdata,
226 MOD_CFG_MAP_SECTION,
227 MOD_CFG_MAP_KEEP_RATIO,
228 SAT_CFG_BOOL_MAP_KEEP_RATIO);
229 col = mod_cfg_get_int(cfgdata,
230 MOD_CFG_MAP_SECTION,
231 MOD_CFG_MAP_INFO_BGD_COL,
232 SAT_CFG_INT_MAP_INFO_BGD_COL);
233
234 satmap->infobgd = rgba2html(col);
235
236 satmap->canvas = goo_canvas_new();
237 g_object_set(G_OBJECT(satmap->canvas), "has-tooltip", TRUE, NULL);
238
239 float clon = (float)mod_cfg_get_int(cfgdata,
240 MOD_CFG_MAP_SECTION,
241 MOD_CFG_MAP_CENTER,
242 SAT_CFG_INT_MAP_CENTER);
243
244 load_map_file(satmap, clon);
245
246 /* Initial size request should be based on map size
247 but if we do this we can not shrink the canvas below this size
248 even though the map shrinks => better to set default size of
249 main container window.
250 */
251 /* gtk_widget_set_size_request (satmap->canvas, */
252 /* gdk_pixbuf_get_width (satmap->origmap), */
253 /* gdk_pixbuf_get_height (satmap->origmap)); */
254
255 goo_canvas_set_bounds(GOO_CANVAS(satmap->canvas), 0, 0,
256 gdk_pixbuf_get_width(satmap->origmap),
257 gdk_pixbuf_get_height(satmap->origmap));
258
259 g_signal_connect(satmap->canvas, "size-allocate",
260 G_CALLBACK(size_allocate_cb), satmap);
261 g_signal_connect(satmap->canvas, "item_created",
262 (GCallback) on_item_created, satmap);
263 g_signal_connect_after(satmap->canvas, "realize",
264 (GCallback) on_canvas_realized, satmap);
265
266 gtk_widget_show(satmap->canvas);
267
268 root = create_canvas_model(satmap);
269 goo_canvas_set_root_item_model(GOO_CANVAS(satmap->canvas), root);
270 g_object_unref(root);
271
272 gtk_sat_map_load_showtracks(satmap);
273 gtk_sat_map_load_hide_coverages(satmap);
274 g_hash_table_foreach(satmap->sats, plot_sat, satmap);
275
276 gtk_box_pack_start(GTK_BOX(satmap), satmap->canvas, TRUE, TRUE, 0);
277
278 return GTK_WIDGET(satmap);
279 }
280
create_canvas_model(GtkSatMap * satmap)281 static GooCanvasItemModel *create_canvas_model(GtkSatMap * satmap)
282 {
283 GooCanvasItemModel *root;
284 gchar *buff;
285 gfloat x, y;
286 guint32 col;
287
288 root = goo_canvas_group_model_new(NULL, NULL);
289
290 /* map dimensions */
291 satmap->width = 200; // was: gdk_pixbuf_get_width (satmap->origmap);
292 satmap->height = 100; // was: gdk_pixbuf_get_height (satmap->origmap);
293 satmap->x0 = 0;
294 satmap->y0 = 0;
295
296 /* background map */
297 satmap->map = goo_canvas_image_model_new(root,
298 satmap->origmap,
299 satmap->x0, satmap->y0, NULL);
300
301 goo_canvas_item_model_lower(satmap->map, NULL);
302 draw_grid_lines(satmap, root);
303
304 if (satmap->show_terminator)
305 draw_terminator(satmap, root);
306
307 /* QTH mark */
308 col = mod_cfg_get_int(satmap->cfgdata,
309 MOD_CFG_MAP_SECTION,
310 MOD_CFG_MAP_QTH_COL, SAT_CFG_INT_MAP_QTH_COL);
311 lonlat_to_xy(satmap, satmap->qth->lon, satmap->qth->lat, &x, &y);
312 satmap->qthmark = goo_canvas_rect_model_new(root,
313 x - MARKER_SIZE_HALF,
314 y - MARKER_SIZE_HALF,
315 2 * MARKER_SIZE_HALF,
316 2 * MARKER_SIZE_HALF,
317 "fill-color-rgba", col,
318 "stroke-color-rgba", col,
319 NULL);
320 satmap->qthlabel = goo_canvas_text_model_new(root, satmap->qth->name,
321 x, y + 2, -1,
322 GOO_CANVAS_ANCHOR_NORTH,
323 "font", "Sans 8",
324 "fill-color-rgba", col, NULL);
325
326 /* QTH info */
327 col = mod_cfg_get_int(satmap->cfgdata,
328 MOD_CFG_MAP_SECTION,
329 MOD_CFG_MAP_INFO_COL, SAT_CFG_INT_MAP_INFO_COL);
330
331 satmap->locnam = goo_canvas_text_model_new(root, "",
332 satmap->x0 + 2, satmap->y0 + 1,
333 -1,
334 GOO_CANVAS_ANCHOR_NORTH_WEST,
335 "font", "Sans 8",
336 "fill-color-rgba", col,
337 "use-markup", TRUE, NULL);
338
339 /* set text only if QTH info is enabled */
340 if (satmap->qthinfo)
341 {
342 /* For now only QTH name and location.
343 It would be nice with coordinates (remember NWSE setting)
344 and Maidenhead locator, when using hamlib.
345
346 Note: I used pango markup to set the background color, I didn't find any
347 other obvious ways to get the text height in pixels to draw rectangle.
348 */
349 buff =
350 g_strdup_printf("<span background=\"#%s\"> %s \302\267 %s </span>",
351 satmap->infobgd, satmap->qth->name,
352 satmap->qth->loc);
353 g_object_set(satmap->locnam, "text", buff, NULL);
354 g_free(buff);
355 }
356
357 /* next event */
358 satmap->next = goo_canvas_text_model_new(root, "",
359 satmap->x0 + satmap->width - 2,
360 satmap->y0 + 1, -1,
361 GOO_CANVAS_ANCHOR_NORTH_EAST,
362 "font", "Sans 8",
363 "fill-color-rgba", col,
364 "use-markup", TRUE, NULL);
365
366 /* set text only if QTH info is enabled */
367 if (satmap->eventinfo)
368 {
369 buff = g_strdup_printf("<span background=\"#%s\"> ... </span>",
370 satmap->infobgd);
371 g_object_set(satmap->next, "text", buff, NULL);
372 g_free(buff);
373 }
374
375 /* cursor track */
376 satmap->curs = goo_canvas_text_model_new(root, "",
377 satmap->x0 + 2,
378 satmap->y0 + satmap->height - 1,
379 -1,
380 GOO_CANVAS_ANCHOR_SOUTH_WEST,
381 "font", "Sans 8",
382 "fill-color-rgba", col,
383 "use-markup", TRUE, NULL);
384
385 /* info about a selected satellite */
386 satmap->sel = goo_canvas_text_model_new(root, "",
387 satmap->x0 + satmap->width - 2,
388 satmap->y0 + satmap->height - 1,
389 -1,
390 GOO_CANVAS_ANCHOR_SOUTH_EAST,
391 "font", "Sans 8",
392 "fill-color-rgba", col,
393 "use-markup", TRUE, NULL);
394
395 return root;
396 }
397
size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation,gpointer data)398 static void size_allocate_cb(GtkWidget * widget, GtkAllocation * allocation,
399 gpointer data)
400 {
401 (void)widget;
402 (void)allocation;
403 GTK_SAT_MAP(data)->resize = TRUE;
404 }
405
update_map_size(GtkSatMap * satmap)406 static void update_map_size(GtkSatMap * satmap)
407 {
408 GtkAllocation allocation;
409 GdkPixbuf *pbuf;
410 gfloat x, y;
411 gfloat ratio; /* ratio between map width and height */
412 gfloat size; /* size = min (alloc.w, ratio*alloc.h) */
413
414 if (gtk_widget_get_realized(GTK_WIDGET(satmap)))
415 {
416 /* get graph dimensions */
417 gtk_widget_get_allocation(GTK_WIDGET(satmap), &allocation);
418
419 if (satmap->keepratio)
420 {
421 /* Use allocation->width and allocation->height to calculate
422 * new X0 Y0 width and height. Map proportions must be kept.
423 */
424 ratio = gdk_pixbuf_get_width(satmap->origmap) /
425 gdk_pixbuf_get_height(satmap->origmap);
426
427 size = MIN(allocation.width, ratio * allocation.height);
428
429 satmap->width = (guint) size;
430 satmap->height = (guint) (size / ratio);
431
432 satmap->x0 = (allocation.width - satmap->width) / 2;
433 satmap->y0 = (allocation.height - satmap->height) / 2;
434
435 /* rescale pixbuf */
436 pbuf = gdk_pixbuf_scale_simple(satmap->origmap,
437 satmap->width,
438 satmap->height,
439 GDK_INTERP_BILINEAR);
440 }
441 else
442 {
443 satmap->x0 = 0;
444 satmap->y0 = 0;
445 satmap->width = allocation.width;
446 satmap->height = allocation.height;
447
448 /* rescale pixbuf */
449 pbuf = gdk_pixbuf_scale_simple(satmap->origmap,
450 satmap->width,
451 satmap->height,
452 GDK_INTERP_BILINEAR);
453 }
454
455 /* set canvas bounds to match new size */
456 goo_canvas_set_bounds(GOO_CANVAS(GTK_SAT_MAP(satmap)->canvas), 0, 0,
457 satmap->width, satmap->height);
458
459
460 /* redraw static elements */
461 g_object_set(satmap->map,
462 "pixbuf", pbuf,
463 "x", (gdouble) satmap->x0,
464 "y", (gdouble) satmap->y0, NULL);
465 g_object_unref(pbuf);
466
467 redraw_grid_lines(satmap);
468
469 if (satmap->show_terminator)
470 redraw_terminator(satmap);
471
472 lonlat_to_xy(satmap, satmap->qth->lon, satmap->qth->lat, &x, &y);
473 g_object_set(satmap->qthmark,
474 "x", x - MARKER_SIZE_HALF,
475 "y", y - MARKER_SIZE_HALF, NULL);
476 g_object_set(satmap->qthlabel, "x", x, "y", y + 2, NULL);
477
478 g_object_set(satmap->locnam,
479 "x", (gdouble) satmap->x0 + 2,
480 "y", (gdouble) satmap->y0 + 1, NULL);
481
482 g_object_set(satmap->next,
483 "x", (gdouble) satmap->x0 + satmap->width - 2,
484 "y", (gdouble) satmap->y0 + 1, NULL);
485
486 g_object_set(satmap->curs,
487 "x", (gdouble) satmap->x0 + 2,
488 "y", (gdouble) satmap->y0 + satmap->height - 1, NULL);
489
490 g_object_set(satmap->sel,
491 "x", (gdouble) satmap->x0 + satmap->width - 2,
492 "y", (gdouble) satmap->y0 + satmap->height - 1, NULL);
493
494 g_hash_table_foreach(satmap->sats, update_sat, satmap);
495 satmap->resize = FALSE;
496 }
497 }
498
on_canvas_realized(GtkWidget * canvas,gpointer data)499 static void on_canvas_realized(GtkWidget * canvas, gpointer data)
500 {
501 GtkSatMap *satmap = GTK_SAT_MAP(data);
502
503 (void)canvas;
504
505 goo_canvas_item_model_raise(satmap->sel, NULL);
506 goo_canvas_item_model_raise(satmap->locnam, NULL);
507 goo_canvas_item_model_raise(satmap->next, NULL);
508 goo_canvas_item_model_raise(satmap->curs, NULL);
509 }
510
511 /* Update the GtkSatMap widget. Called periodically from GtkSatModule. */
gtk_sat_map_update(GtkWidget * widget)512 void gtk_sat_map_update(GtkWidget * widget)
513 {
514 GtkSatMap *satmap = GTK_SAT_MAP(widget);
515 sat_t *sat = NULL;
516 gdouble number, now;
517 gchar *buff;
518 gint *catnr;
519 guint h, m, s;
520 gchar *ch, *cm, *cs;
521 gfloat x, y;
522 gdouble oldx, oldy;
523
524 /* check whether there are any pending resize requests */
525 if (satmap->resize)
526 update_map_size(satmap);
527
528 /* check if qth has moved significantly, if so move it */
529 lonlat_to_xy(satmap, satmap->qth->lon, satmap->qth->lat, &x, &y);
530 g_object_get(satmap->qthmark, "x", &oldx, "y", &oldy, NULL);
531
532 if ((fabs(oldx - x) >= 2 * MARKER_SIZE_HALF) ||
533 (fabs(oldy - y) >= 2 * MARKER_SIZE_HALF))
534 {
535 g_object_set(satmap->qthmark,
536 "x", x - MARKER_SIZE_HALF,
537 "y", y - MARKER_SIZE_HALF, NULL);
538 g_object_set(satmap->qthlabel, "x", x, "y", y + 2, NULL);
539 g_object_set(satmap->locnam,
540 "x", (gdouble) satmap->x0 + 2,
541 "y", (gdouble) satmap->y0 + 1, NULL);
542 satmap->counter = satmap->refresh;
543 }
544
545 /* check refresh rate and refresh sats/qth if time */
546 /* FIXME add location check */
547 if (satmap->counter < satmap->refresh)
548 {
549 satmap->counter++;
550 }
551 else
552 {
553 /* reset data */
554 satmap->counter = 1;
555 satmap->naos = 0.0;
556 satmap->ncat = 0;
557
558 lonlat_to_xy(satmap, satmap->qth->lon, satmap->qth->lat, &x, &y);
559 g_object_set(satmap->qthmark,
560 "x", x - MARKER_SIZE_HALF,
561 "y", y - MARKER_SIZE_HALF, NULL);
562 g_object_set(satmap->qthlabel, "x", x, "y", y + 2, NULL);
563 g_object_set(satmap->locnam,
564 "x", (gdouble) satmap->x0 + 2,
565 "y", (gdouble) satmap->y0 + 1, NULL);
566
567 g_hash_table_foreach(satmap->sats, update_sat, satmap);
568
569 /* Update the Solar Terminator if necessary */
570 if (satmap->show_terminator &&
571 fabs(satmap->tstamp - satmap->terminator_last_tstamp) >
572 TERMINATOR_UPDATE_INTERVAL)
573 {
574 satmap->terminator_last_tstamp = satmap->tstamp;
575 redraw_terminator(satmap);
576 }
577
578 if (satmap->eventinfo)
579 {
580 if (satmap->ncat > 0)
581 {
582 catnr = g_try_new0(gint, 1);
583 *catnr = satmap->ncat;
584 sat = SAT(g_hash_table_lookup(satmap->sats, catnr));
585 g_free(catnr);
586
587 /* last desperate sanity check */
588 if (sat != NULL)
589 {
590 now = satmap->tstamp; //get_current_daynum ();
591 number = satmap->naos - now;
592
593 /* convert julian date to seconds */
594 s = (guint) (number * 86400);
595
596 /* extract hours */
597 h = (guint) floor(s / 3600);
598 s -= 3600 * h;
599
600 /* leading zero */
601 if ((h > 0) && (h < 10))
602 ch = g_strdup("0");
603 else
604 ch = g_strdup("");
605
606 /* extract minutes */
607 m = (guint) floor(s / 60);
608 s -= 60 * m;
609
610 /* leading zero */
611 if (m < 10)
612 cm = g_strdup("0");
613 else
614 cm = g_strdup("");
615
616 /* leading zero */
617 if (s < 10)
618 cs = g_strdup(":0");
619 else
620 cs = g_strdup(":");
621
622 if (h > 0)
623 buff =
624 g_markup_printf_escaped(_
625 ("<span background=\"#%s\"> "
626 "Next: %s in %s%d:%s%d%s%d </span>"),
627 satmap->infobgd,
628 sat->nickname, ch, h, cm,
629 m, cs, s);
630 else
631 buff =
632 g_markup_printf_escaped(_
633 ("<span background=\"#%s\"> "
634 "Next: %s in %s%d%s%d </span>"),
635 satmap->infobgd,
636 sat->nickname, cm, m, cs,
637 s);
638
639 g_object_set(satmap->next, "text", buff, NULL);
640
641 g_free(buff);
642 g_free(ch);
643 g_free(cm);
644 g_free(cs);
645 }
646 else
647 {
648 sat_log_log(SAT_LOG_LEVEL_ERROR,
649 _("%s: Can not find NEXT satellite."),
650 __func__);
651 g_object_set(satmap->next, "text", _("Next: ERR"), NULL);
652 }
653 }
654 else
655 {
656 g_object_set(satmap->next, "text", _("Next: N/A"), NULL);
657 }
658 }
659 else
660 {
661 g_object_set(satmap->next, "text", "", NULL);
662 }
663 }
664 }
665
666 /* Assumes that -180 <= lon <= 180 and -90 <= lat <= 90 */
lonlat_to_xy(GtkSatMap * p,gdouble lon,gdouble lat,gfloat * x,gfloat * y)667 static void lonlat_to_xy(GtkSatMap * p, gdouble lon, gdouble lat, gfloat * x,
668 gfloat * y)
669 {
670 *x = p->x0 + (lon - p->left_side_lon) * p->width / 360.0;
671 *y = p->y0 + (90.0 - lat) * p->height / 180.0;
672 while (*x < 0)
673 {
674 *x += p->width;
675 }
676 while (*x > p->width)
677 {
678 *x -= p->width;
679 }
680 }
681
xy_to_lonlat(GtkSatMap * p,gfloat x,gfloat y,gfloat * lon,gfloat * lat)682 static void xy_to_lonlat(GtkSatMap * p, gfloat x, gfloat y, gfloat * lon,
683 gfloat * lat)
684 {
685 *lat = 90.0 - (180.0 / p->height) * (y - p->y0);
686 *lon = (360.0 / p->width) * (x - p->x0) + p->left_side_lon;
687 while (*lon > 180)
688 {
689 *lon -= 360;
690 }
691 while (*lon < -180)
692 {
693 *lon += 360;
694 }
695 }
696
on_motion_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEventMotion * event,gpointer data)697 static gboolean on_motion_notify(GooCanvasItem * item,
698 GooCanvasItem * target,
699 GdkEventMotion * event, gpointer data)
700 {
701 GtkSatMap *satmap = GTK_SAT_MAP(data);
702 gfloat lat, lon;
703 gchar *text;
704
705 (void)target;
706 (void)item;
707
708 /* set text only if QTH info is enabled */
709 if (satmap->cursinfo)
710 {
711 xy_to_lonlat(satmap, event->x, event->y, &lon, &lat);
712
713 /* cursor track */
714 text = g_strdup_printf("<span background=\"#%s\"> "
715 "LON:%.0f\302\260 LAT:%.0f\302\260 </span>",
716 satmap->infobgd, lon, lat);
717
718 g_object_set(satmap->curs, "text", text, NULL);
719 g_free(text);
720 }
721
722 return TRUE;
723 }
724
725 /*
726 * Finish canvas item setup.
727 *
728 * This function is called when a canvas item is created. Its purpose is to connect
729 * the corresponding signals to the created items.
730 *
731 * The root item, ie the background is connected to motion notify event, while other
732 * items (sats) are connected to mouse click events.
733 *
734 * @bug Should filter out QTH or do we want to click on the QTH?
735 */
on_item_created(GooCanvas * canvas,GooCanvasItem * item,GooCanvasItemModel * model,gpointer data)736 static void on_item_created(GooCanvas * canvas,
737 GooCanvasItem * item,
738 GooCanvasItemModel * model, gpointer data)
739 {
740 (void)canvas;
741 if (!goo_canvas_item_model_get_parent(model))
742 {
743 /* root item / canvas */
744 g_signal_connect(item, "motion_notify_event",
745 (GCallback) on_motion_notify, data);
746 }
747 else if (!g_object_get_data(G_OBJECT(item), "skip-signal-connection"))
748 {
749 g_signal_connect(item, "button_press_event",
750 (GCallback) on_button_press, data);
751 g_signal_connect(item, "button_release_event",
752 (GCallback) on_button_release, data);
753 }
754 }
755
on_button_press(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)756 static gboolean on_button_press(GooCanvasItem * item,
757 GooCanvasItem * target, GdkEventButton * event,
758 gpointer data)
759 {
760 GooCanvasItemModel *model = goo_canvas_item_get_model(item);
761 GtkSatMap *satmap = GTK_SAT_MAP(data);
762 gint catnum =
763 GPOINTER_TO_INT(g_object_get_data(G_OBJECT(model), "catnum"));
764 gint *catpoint = NULL;
765 sat_t *sat = NULL;
766
767 (void)target;
768
769 switch (event->button)
770 {
771 /* double-left-click */
772 case 1:
773 if (event->type == GDK_2BUTTON_PRESS)
774 {
775 catpoint = g_try_new0(gint, 1);
776 *catpoint = catnum;
777
778 sat = SAT(g_hash_table_lookup(satmap->sats, catpoint));
779 if (sat != NULL)
780 {
781 show_sat_info(sat, gtk_widget_get_toplevel(GTK_WIDGET(data)));
782 }
783 else
784 {
785 /* double-clicked on map */
786 }
787 }
788 g_free(catpoint);
789 break;
790
791 /* pop-up menu */
792 case 3:
793 catpoint = g_try_new0(gint, 1);
794 *catpoint = catnum;
795 sat = SAT(g_hash_table_lookup(satmap->sats, catpoint));
796 if (sat != NULL)
797 {
798 gtk_sat_map_popup_exec(sat, satmap->qth, satmap, event,
799 gtk_widget_get_toplevel(GTK_WIDGET
800 (satmap)));
801 }
802 else
803 {
804 /* clicked on map -> map pop-up in the future */
805 }
806 g_free(catpoint);
807 break;
808 default:
809 break;
810 }
811
812 return TRUE;
813 }
814
on_button_release(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)815 static gboolean on_button_release(GooCanvasItem * item,
816 GooCanvasItem * target,
817 GdkEventButton * event, gpointer data)
818 {
819 GooCanvasItemModel *model = goo_canvas_item_get_model(item);
820 GtkSatMap *satmap = GTK_SAT_MAP(data);
821 gint catnum =
822 GPOINTER_TO_INT(g_object_get_data(G_OBJECT(model), "catnum"));
823 gint *catpoint = NULL;
824 sat_map_obj_t *obj = NULL;
825 guint32 col;
826
827 (void)target;
828
829 catpoint = g_try_new0(gint, 1);
830 *catpoint = catnum;
831
832 switch (event->button)
833 {
834 /* Select / de-select satellite */
835 case 1:
836 obj = SAT_MAP_OBJ(g_hash_table_lookup(satmap->obj, catpoint));
837 if (obj == NULL)
838 {
839 sat_log_log(SAT_LOG_LEVEL_ERROR,
840 _
841 ("%s:%d: Can not find clicked object (%d) in hash table"),
842 __FILE__, __LINE__, catnum);
843 }
844 else
845 {
846 obj->selected = !obj->selected;
847
848 if (obj->selected)
849 {
850 col = mod_cfg_get_int(satmap->cfgdata,
851 MOD_CFG_MAP_SECTION,
852 MOD_CFG_MAP_SAT_SEL_COL,
853 SAT_CFG_INT_MAP_SAT_SEL_COL);
854 }
855 else
856 {
857 col = mod_cfg_get_int(satmap->cfgdata,
858 MOD_CFG_MAP_SECTION,
859 MOD_CFG_MAP_SAT_COL,
860 SAT_CFG_INT_MAP_SAT_COL);
861 *catpoint = 0;
862
863 g_object_set(satmap->sel, "text", "", NULL);
864 }
865
866 g_object_set(obj->marker,
867 "fill-color-rgba", col,
868 "stroke-color-rgba", col, NULL);
869 g_object_set(obj->label,
870 "fill-color-rgba", col,
871 "stroke-color-rgba", col, NULL);
872 g_object_set(obj->range1, "stroke-color-rgba", col, NULL);
873
874 if (obj->oldrcnum == 2)
875 g_object_set(obj->range2, "stroke-color-rgba", col, NULL);
876
877 /* clear other selections */
878 g_hash_table_foreach(satmap->obj, clear_selection, catpoint);
879 }
880 break;
881 default:
882 break;
883 }
884
885 g_free(catpoint);
886
887 return TRUE;
888 }
889
clear_selection(gpointer key,gpointer val,gpointer data)890 static void clear_selection(gpointer key, gpointer val, gpointer data)
891 {
892 gint *old = key;
893 gint *new = data;
894 sat_map_obj_t *obj = SAT_MAP_OBJ(val);
895 guint32 col;
896
897 if ((*old != *new) && (obj->selected))
898 {
899 obj->selected = FALSE;
900
901 /** FIXME: this is only global default; need the satmap here! */
902 col = sat_cfg_get_int(SAT_CFG_INT_MAP_SAT_COL);
903
904 g_object_set(obj->marker,
905 "fill-color-rgba", col, "stroke-color-rgba", col, NULL);
906 g_object_set(obj->label,
907 "fill-color-rgba", col, "stroke-color-rgba", col, NULL);
908 g_object_set(obj->range1, "stroke-color-rgba", col, NULL);
909
910 if (obj->oldrcnum == 2)
911 g_object_set(obj->range2, "stroke-color-rgba", col, NULL);
912 }
913 }
914
gtk_sat_map_select_sat(GtkWidget * satmap,gint catnum)915 void gtk_sat_map_select_sat(GtkWidget * satmap, gint catnum)
916 {
917 GtkSatMap *smap = GTK_SAT_MAP(satmap);
918 gint *catpoint = NULL;
919 sat_map_obj_t *obj = NULL;
920 guint32 col;
921
922 catpoint = g_try_new0(gint, 1);
923 *catpoint = catnum;
924
925 obj = SAT_MAP_OBJ(g_hash_table_lookup(smap->obj, catpoint));
926 if (obj == NULL)
927 {
928 sat_log_log(SAT_LOG_LEVEL_ERROR,
929 _("%s: Can not find clicked object (%d) in hash table"),
930 __func__, catnum);
931 }
932 else
933 {
934 obj->selected = TRUE;
935
936 col = mod_cfg_get_int(smap->cfgdata,
937 MOD_CFG_MAP_SECTION,
938 MOD_CFG_MAP_SAT_SEL_COL,
939 SAT_CFG_INT_MAP_SAT_SEL_COL);
940
941 g_object_set(obj->marker,
942 "fill-color-rgba", col, "stroke-color-rgba", col, NULL);
943 g_object_set(obj->label,
944 "fill-color-rgba", col, "stroke-color-rgba", col, NULL);
945 g_object_set(obj->range1, "stroke-color-rgba", col, NULL);
946
947 if (obj->oldrcnum == 2)
948 g_object_set(obj->range2, "stroke-color-rgba", col, NULL);
949
950 /* clear other selections */
951 g_hash_table_foreach(smap->obj, clear_selection, catpoint);
952 }
953
954 g_free(catpoint);
955 }
956
957 /*
958 * Reconfigure map.
959 *
960 * This function should eventually reload all configuration for the GtkSatMap.
961 * Currently this function is not implemented for any of the views. Reconfiguration
962 * is done by recreating the whole module.
963 */
gtk_sat_map_reconf(GtkWidget * widget,GKeyFile * cfgdat)964 void gtk_sat_map_reconf(GtkWidget * widget, GKeyFile * cfgdat)
965 {
966 (void)widget;
967 (void)cfgdat;
968 }
969
970 /*
971 * Safely load a map file.
972 *
973 * @param satmap The GtkSatMap widget
974 * @param clon The longitude that should be the center of the map
975 *
976 * This function is called shortly after the canvas has been created. Its purpose
977 * is to load a mapfile into satmap->origmap.
978 *
979 * The function ensures that satmap->origmap will contain a valid GdkPixpuf, by
980 * using the following logic:
981 *
982 * - Get either module specific or global map file using mod_cfg_get_str
983 * - If the returned file does not exist try sat_cfg_get_str_def
984 * - If loading of default map does not succeed, create a dummy GdkPixbuf
985 * (and raise all possible alarms)
986 *
987 * @note satmap->cfgdata should contain a valid GKeyFile.
988 *
989 */
load_map_file(GtkSatMap * satmap,float clon)990 static void load_map_file(GtkSatMap * satmap, float clon)
991 {
992 gchar *buff;
993 gchar *mapfile;
994 GError *error = NULL;
995 GdkPixbuf *tmpbuf;
996
997 /* get local, global or default map file */
998 buff = mod_cfg_get_str(satmap->cfgdata,
999 MOD_CFG_MAP_SECTION,
1000 MOD_CFG_MAP_FILE, SAT_CFG_STR_MAP_FILE);
1001
1002 if (g_path_is_absolute(buff))
1003 {
1004 /* map is user specific, ie. in $HOME/.gpredict2/maps/ */
1005 mapfile = g_strdup(buff);
1006 }
1007 else
1008 {
1009 /* build complete path */
1010 mapfile = map_file_name(buff);
1011 }
1012 g_free(buff);
1013
1014 sat_log_log(SAT_LOG_LEVEL_DEBUG,
1015 _("%s:%d: Loading map file %s"), __FILE__, __LINE__, mapfile);
1016
1017 /* check that file exists, if not get the default */
1018 if (g_file_test(mapfile, G_FILE_TEST_EXISTS))
1019 {
1020 sat_log_log(SAT_LOG_LEVEL_DEBUG,
1021 _("%s:%d: Map file found"), __FILE__, __LINE__);
1022 }
1023 else
1024 {
1025 sat_log_log(SAT_LOG_LEVEL_ERROR,
1026 _("%s:%d: Could not find map file %s"),
1027 __FILE__, __LINE__, mapfile);
1028
1029 /* get default map file */
1030 g_free(mapfile);
1031 mapfile = sat_cfg_get_str_def(SAT_CFG_STR_MAP_FILE);
1032
1033 sat_log_log(SAT_LOG_LEVEL_ERROR,
1034 _("%s:%d: Using default map: %s"),
1035 __FILE__, __LINE__, mapfile);
1036 }
1037
1038 /* try to load the map file */
1039 tmpbuf = gdk_pixbuf_new_from_file(mapfile, &error);
1040
1041 if (error != NULL)
1042 {
1043 sat_log_log(SAT_LOG_LEVEL_ERROR,
1044 _("%s:%d: Error loading map file (%s)"),
1045 __FILE__, __LINE__, error->message);
1046 g_clear_error(&error);
1047
1048 /* create a dummy GdkPixbuf to avoid crash */
1049 tmpbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 400, 200);
1050 gdk_pixbuf_fill(tmpbuf, 0x0F0F0F0F);
1051 }
1052
1053 /* create a blank map with same parameters as tmpbuf */
1054 satmap->origmap = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1055 FALSE,
1056 gdk_pixbuf_get_bits_per_sample(tmpbuf),
1057 gdk_pixbuf_get_width(tmpbuf),
1058 gdk_pixbuf_get_height(tmpbuf));
1059
1060 map_tools_shift_center(tmpbuf, satmap->origmap, clon);
1061 g_object_unref(tmpbuf);
1062 g_free(mapfile);
1063
1064 /* Calculate longitude at the left side (-180 deg if center is at 0 deg longitude) */
1065 satmap->left_side_lon = -180.0;
1066 if (clon > 0.0)
1067 satmap->left_side_lon += clon;
1068 else if (clon < 0.0)
1069 satmap->left_side_lon = 180.0 + clon;
1070 }
1071
arccos(gdouble x,gdouble y)1072 static gdouble arccos(gdouble x, gdouble y)
1073 {
1074 if (x && y)
1075 {
1076 if (y > 0.0)
1077 return acos(x / y);
1078 else if (y < 0.0)
1079 return pi + acos(x / y);
1080 }
1081
1082 return 0.0;
1083 }
1084
1085 /* Check whether the footprint covers the North or South pole. */
pole_is_covered(sat_t * sat)1086 static gboolean pole_is_covered(sat_t * sat)
1087 {
1088 if (north_pole_is_covered(sat) || south_pole_is_covered(sat))
1089 return TRUE;
1090 else
1091 return FALSE;
1092 }
1093
1094 /* Check whether the footprint covers the North pole. */
north_pole_is_covered(sat_t * sat)1095 static gboolean north_pole_is_covered(sat_t * sat)
1096 {
1097 int ret1;
1098 gdouble qrb1, az1;
1099
1100 ret1 = qrb(sat->ssplon, sat->ssplat, 0.0, 90.0, &qrb1, &az1);
1101 if (ret1 != RIG_OK)
1102 {
1103 sat_log_log(SAT_LOG_LEVEL_ERROR,
1104 _("%s: Bad data measuring distance to North Pole %f %f."),
1105 __func__, sat->ssplon, sat->ssplat);
1106 }
1107 if (qrb1 <= 0.5 * sat->footprint)
1108 {
1109 return TRUE;
1110 }
1111 return FALSE;
1112 }
1113
1114 /* Check whether the footprint covers the South pole. */
south_pole_is_covered(sat_t * sat)1115 static gboolean south_pole_is_covered(sat_t * sat)
1116 {
1117 int ret1;
1118 gdouble qrb1, az1;
1119
1120 ret1 = qrb(sat->ssplon, sat->ssplat, 0.0, -90.0, &qrb1, &az1);
1121 if (ret1 != RIG_OK)
1122 {
1123 sat_log_log(SAT_LOG_LEVEL_ERROR,
1124 _("%s: Bad data measuring distance to South Pole %f %f."),
1125 __func__, sat->ssplon, sat->ssplat);
1126 }
1127 if (qrb1 <= 0.5 * sat->footprint)
1128 {
1129 return TRUE;
1130 }
1131 return FALSE;
1132 }
1133
1134 /* Mirror the footprint longitude. */
mirror_lon(sat_t * sat,gdouble rangelon,gdouble * mlon,gdouble mapbreak)1135 static gboolean mirror_lon(sat_t * sat, gdouble rangelon, gdouble * mlon,
1136 gdouble mapbreak)
1137 {
1138 gdouble diff;
1139 gboolean warped = FALSE;
1140
1141 /* make it so rangelon is on left of ssplon */
1142 diff = (sat->ssplon - rangelon);
1143 while (diff < 0)
1144 diff += 360;
1145 while (diff > 360)
1146 diff -= 360;
1147
1148 *mlon = sat->ssplon + fabs(diff);
1149 while (*mlon > 180)
1150 *mlon -= 360;
1151 while (*mlon < -180)
1152 *mlon += 360;
1153 //printf("Something %s %f %f %f\n",sat->nickname, sat->ssplon, rangelon,mapbreak);
1154 if (((sat->ssplon >= mapbreak) && (sat->ssplon < mapbreak + 180)) ||
1155 ((sat->ssplon < mapbreak - 180) && (sat->ssplon >= mapbreak - 360)))
1156 {
1157 if (((rangelon >= mapbreak) && (rangelon < mapbreak + 180)) ||
1158 ((rangelon < mapbreak - 180) && (rangelon >= mapbreak - 360)))
1159 {
1160 }
1161 else
1162 {
1163 warped = TRUE;
1164 //printf ("sat %s warped for first \n",sat->nickname);
1165 }
1166 }
1167 else
1168 {
1169 if (((*mlon >= mapbreak) && (*mlon < mapbreak + 180)) ||
1170 ((*mlon < mapbreak - 180) && (*mlon >= mapbreak - 360)))
1171 {
1172 warped = TRUE;
1173 //printf ("sat %s warped for second \n",sat->nickname);
1174 }
1175 }
1176
1177 return warped;
1178 }
1179
1180 /**
1181 * Calculate satellite footprint and coverage area.
1182 *
1183 * @param satmap TheGtkSatMap widget.
1184 * @param sat The satellite.
1185 * @param points1 Initialised GooCanvasPoints structure with 360 points.
1186 * @param points2 Initialised GooCanvasPoints structure with 360 points.
1187 * @return The number of range circle parts.
1188 *
1189 * This function calculates the "left" side of the range circle and mirrors
1190 * the points in longitude to create the "right side of the range circle, too.
1191 * In order to be able to use the footprint points to create a set of subsequent
1192 * lines conencted to each other (poly-lines) the function may have to perform
1193 * one of the following three actions:
1194 *
1195 * 1. If the footprint covers the North or South pole, we need to sort the points
1196 * and add two extra points: One to begin the range circle (e.g. -180,90) and
1197 * one to end the range circle (e.g. 180,90). This is necessary to create a
1198 * complete and consistent set of points suitable for a polyline. The addition
1199 * of the extra points is done by the sort_points function.
1200 *
1201 * 2. Else if parts of the range circle is on one side of the map, while parts of
1202 * it is on the right side of the map, i.e. the range circle runs off the border
1203 * of the map, it calls the split_points function to split the points into two
1204 * complete and consistent sets of points that are suitable to create two
1205 * poly-lines.
1206 *
1207 * 3. Else nothing needs to be done since the points are already suitable for
1208 * a polyline.
1209 *
1210 * The function will re-initialise points1 and points2 according to its needs. The
1211 * total number of points will always be 360, even with the addition of the two
1212 * extra points.
1213 */
calculate_footprint(GtkSatMap * satmap,sat_t * sat)1214 static guint calculate_footprint(GtkSatMap * satmap, sat_t * sat)
1215 {
1216 guint azi;
1217 gfloat sx, sy, msx, msy, ssx, ssy;
1218 gdouble ssplat, ssplon, beta, azimuth, num, dem;
1219 gdouble rangelon, rangelat, mlon;
1220 gboolean warped = FALSE;
1221 guint numrc = 1;
1222
1223 /* Range circle calculations.
1224 * Borrowed from gsat 0.9.0 by Xavier Crehueras, EB3CZS
1225 * who borrowed from John Magliacane, KD2BD.
1226 * Optimized by Alexandru Csete and William J Beksi.
1227 */
1228 ssplat = sat->ssplat * de2ra;
1229 ssplon = sat->ssplon * de2ra;
1230 beta = (0.5 * sat->footprint) / xkmper;
1231
1232 for (azi = 0; azi < 180; azi++)
1233 {
1234 azimuth = de2ra * (double)azi;
1235 rangelat = asin(sin(ssplat) * cos(beta) + cos(azimuth) *
1236 sin(beta) * cos(ssplat));
1237 num = cos(beta) - (sin(ssplat) * sin(rangelat));
1238 dem = cos(ssplat) * cos(rangelat);
1239
1240 if (azi == 0 && north_pole_is_covered(sat))
1241 rangelon = ssplon + pi;
1242 else if (fabs(num / dem) > 1.0)
1243 rangelon = ssplon;
1244 else
1245 {
1246 if ((180.0 - azi) >= 0)
1247 rangelon = ssplon - arccos(num, dem);
1248 else
1249 rangelon = ssplon + arccos(num, dem);
1250 }
1251
1252 while (rangelon < -pi)
1253 rangelon += twopi;
1254
1255 while (rangelon > (pi))
1256 rangelon -= twopi;
1257
1258 rangelat = rangelat / de2ra;
1259 rangelon = rangelon / de2ra;
1260
1261 /* mirror longitude */
1262 if (mirror_lon(sat, rangelon, &mlon, satmap->left_side_lon))
1263 warped = TRUE;
1264
1265 lonlat_to_xy(satmap, rangelon, rangelat, &sx, &sy);
1266 lonlat_to_xy(satmap, mlon, rangelat, &msx, &msy);
1267
1268 points1->coords[2 * azi] = sx;
1269 points1->coords[2 * azi + 1] = sy;
1270
1271 /* Add mirrored point */
1272 points1->coords[718 - 2 * azi] = msx;
1273 points1->coords[719 - 2 * azi] = msy;
1274 }
1275
1276 /* points1 now contains 360 pairs of map-based XY coordinates.
1277 Check whether actions 1, 2 or 3 have to be performed.
1278 */
1279
1280 /* pole is covered => sort points1 and add additional points */
1281 if (pole_is_covered(sat))
1282 {
1283
1284 sort_points_x(satmap, sat, points1, 360);
1285 numrc = 1;
1286 }
1287
1288 /* pole not covered but range circle has been warped
1289 => split points */
1290 else if (warped == TRUE)
1291 {
1292
1293 lonlat_to_xy(satmap, sat->ssplon, sat->ssplat, &ssx, &ssy);
1294 split_points(satmap, sat, ssx);
1295 numrc = 2;
1296
1297 }
1298 else
1299 {
1300 /* the nominal condition => points1 is adequate */
1301 numrc = 1;
1302 }
1303
1304 return numrc;
1305 }
1306
1307 /**
1308 * Split and sort polyline points.
1309 *
1310 * @param satmap The GtkSatMap structure.
1311 * @param points1 GooCanvasPoints containing the footprint points.
1312 * @param points2 A GooCanvasPoints structure containing the second set of points.
1313 * @param sspx Canvas based x-coordinate of SSP.
1314 * @bug We should ensure that the endpoints in points1 have x=x0, while in
1315 * the endpoints in points2 should have x=x0+width (TBC).
1316 *
1317 * @note This function works on canvas-based coordinates rather than lat/lon
1318 * @note DO NOT USE this function when the footprint covers one of the poles
1319 * (the end result may freeze the X-server requiring a hard-reset!)
1320 */
split_points(GtkSatMap * satmap,sat_t * sat,gdouble sspx)1321 static void split_points(GtkSatMap * satmap, sat_t * sat, gdouble sspx)
1322 {
1323 GooCanvasPoints *tps1, *tps2;
1324 gint n, n1, n2, ns, i, j, k;
1325
1326 /* initialize parameters */
1327 n = points1->num_points;
1328 n1 = 0;
1329 n2 = 0;
1330 i = 0;
1331 j = 0;
1332 k = 0;
1333 ns = 0;
1334 tps1 = goo_canvas_points_new(n);
1335 tps2 = goo_canvas_points_new(n);
1336
1337 //if ((sspx >= (satmap->x0 + satmap->width - 0.6)) ||
1338 // (sspx >= (satmap->x0 - 0.6))) {
1339 //if ((sspx == (satmap->x0 + satmap->width)) ||
1340 // (sspx == (satmap->x0))) {
1341 if ((sat->ssplon >= 179.4) || (sat->ssplon <= -179.4))
1342 {
1343 /* sslon = +/-180 deg.
1344 - copy points with (x > satmap->x0+satmap->width/2) to tps1
1345 - copy points with (x < satmap->x0+satmap->width/2) to tps2
1346 - sort tps1 and tps2
1347 */
1348 for (i = 0; i < n; i++)
1349 {
1350 if (points1->coords[2 * i] > (satmap->x0 + satmap->width / 2))
1351 {
1352 tps1->coords[2 * n1] = points1->coords[2 * i];
1353 tps1->coords[2 * n1 + 1] = points1->coords[2 * i + 1];
1354 n1++;
1355 }
1356 else
1357 {
1358 tps2->coords[2 * n2] = points1->coords[2 * i];
1359 tps2->coords[2 * n2 + 1] = points1->coords[2 * i + 1];
1360 n2++;
1361 }
1362 }
1363
1364 sort_points_y(satmap, sat, tps1, n1);
1365 sort_points_y(satmap, sat, tps2, n2);
1366 }
1367 else if (sspx < (satmap->x0 + satmap->width / 2))
1368 {
1369 /* We are on the left side of the map.
1370 Scan through points1 until we get to x > sspx (i=ns):
1371
1372 - copy the points forwards until x < (x0+w/2) => tps2
1373 - continue to copy until the end => tps1
1374 - copy the points from i=0 to i=ns => tps1.
1375
1376 Copy tps1 => points1 and tps2 => points2
1377 */
1378 while (points1->coords[2 * i] <= sspx)
1379 {
1380 i++;
1381 }
1382 ns = i - 1;
1383
1384 while (points1->coords[2 * i] > (satmap->x0 + satmap->width / 2))
1385 {
1386 tps2->coords[2 * j] = points1->coords[2 * i];
1387 tps2->coords[2 * j + 1] = points1->coords[2 * i + 1];
1388 i++;
1389 j++;
1390 n2++;
1391 }
1392
1393 while (i < n)
1394 {
1395 tps1->coords[2 * k] = points1->coords[2 * i];
1396 tps1->coords[2 * k + 1] = points1->coords[2 * i + 1];
1397 i++;
1398 k++;
1399 n1++;
1400 }
1401
1402 for (i = 0; i <= ns; i++)
1403 {
1404 tps1->coords[2 * k] = points1->coords[2 * i];
1405 tps1->coords[2 * k + 1] = points1->coords[2 * i + 1];
1406 k++;
1407 n1++;
1408 }
1409 }
1410 else
1411 {
1412 /* We are on the right side of the map.
1413 Scan backwards through points1 until x < sspx (i=ns):
1414
1415 - copy the points i=ns,i-- until x >= x0+w/2 => tps2
1416 - copy the points until we reach i=0 => tps1
1417 - copy the points from i=n to i=ns => tps1
1418
1419 */
1420 i = n - 1;
1421 while (points1->coords[2 * i] >= sspx)
1422 {
1423 i--;
1424 }
1425 ns = i + 1;
1426
1427 while (points1->coords[2 * i] < (satmap->x0 + satmap->width / 2))
1428 {
1429 tps2->coords[2 * j] = points1->coords[2 * i];
1430 tps2->coords[2 * j + 1] = points1->coords[2 * i + 1];
1431 i--;
1432 j++;
1433 n2++;
1434 }
1435
1436 while (i >= 0)
1437 {
1438 tps1->coords[2 * k] = points1->coords[2 * i];
1439 tps1->coords[2 * k + 1] = points1->coords[2 * i + 1];
1440 i--;
1441 k++;
1442 n1++;
1443 }
1444
1445 for (i = n - 1; i >= ns; i--)
1446 {
1447 tps1->coords[2 * k] = points1->coords[2 * i];
1448 tps1->coords[2 * k + 1] = points1->coords[2 * i + 1];
1449 k++;
1450 n1++;
1451 }
1452 }
1453
1454 //g_print ("NS:%d N1:%d N2:%d\n", ns, n1, n2);
1455
1456 /* free points and copy new contents */
1457 goo_canvas_points_unref(points1);
1458 goo_canvas_points_unref(points2);
1459
1460 points1 = goo_canvas_points_new(n1);
1461 for (i = 0; i < n1; i++)
1462 {
1463 points1->coords[2 * i] = tps1->coords[2 * i];
1464 points1->coords[2 * i + 1] = tps1->coords[2 * i + 1];
1465 }
1466 goo_canvas_points_unref(tps1);
1467
1468 points2 = goo_canvas_points_new(n2);
1469 for (i = 0; i < n2; i++)
1470 {
1471 points2->coords[2 * i] = tps2->coords[2 * i];
1472 points2->coords[2 * i + 1] = tps2->coords[2 * i + 1];
1473 }
1474 goo_canvas_points_unref(tps2);
1475
1476 /* stretch end points to map borders */
1477 if (points1->coords[0] > (satmap->x0 + satmap->width / 2))
1478 {
1479 points1->coords[0] = satmap->x0 + satmap->width;
1480 points1->coords[2 * (n1 - 1)] = satmap->x0 + satmap->width;
1481 points2->coords[0] = satmap->x0;
1482 points2->coords[2 * (n2 - 1)] = satmap->x0;
1483 }
1484 else
1485 {
1486 points2->coords[0] = satmap->x0 + satmap->width;
1487 points2->coords[2 * (n2 - 1)] = satmap->x0 + satmap->width;
1488 points1->coords[0] = satmap->x0;
1489 points1->coords[2 * (n1 - 1)] = satmap->x0;
1490 }
1491 }
1492
1493 /**
1494 * Sort points according to X coordinates.
1495 *
1496 * @param satmap The GtkSatMap structure.
1497 * @param sat The satellite data structure.
1498 * @param points The points to sort.
1499 * @param num The number of points. By specifying it as parameter we can
1500 * sort incomplete arrays.
1501 *
1502 * This function sorts the points in ascending order with respect
1503 * to their x value. After sorting the function adds two extra points
1504 * to the array using the following algorithms:
1505 *
1506 * move point at position 0 to position 1
1507 * move point at position N to position N-1
1508 * if (ssplat > 0)
1509 * insert (x0,y0) into position 0
1510 * insert (x0+width,y0) into position N
1511 * else
1512 * insert (x0,y0+height) into position 0
1513 * insert (x0+width,y0+height) into position N
1514 *
1515 * This way we loose the points at position 1 and N-1, but that does not
1516 * make any big difference anyway, since we have 360 points in total.
1517 *
1518 */
sort_points_x(GtkSatMap * satmap,sat_t * sat,GooCanvasPoints * points,gint num)1519 static void sort_points_x(GtkSatMap * satmap, sat_t * sat,
1520 GooCanvasPoints * points, gint num)
1521 {
1522 gsize size = 2 * sizeof(double);
1523
1524 /* call g_qsort_with_data, which warps the qsort function
1525 from stdlib */
1526 g_qsort_with_data(points->coords, num, size, compare_coordinates_x, NULL);
1527
1528 /* move point at position 0 to position 1 */
1529 points->coords[2] = satmap->x0;
1530 points->coords[3] = points->coords[1];
1531
1532 /* move point at position N to position N-1 */
1533 points->coords[716] = satmap->x0 + satmap->width; //points->coords[718];
1534 points->coords[717] = points->coords[719];
1535
1536 if (sat->ssplat > 0.0)
1537 {
1538 /* insert (x0-1,y0) into position 0 */
1539 points->coords[0] = satmap->x0;
1540 points->coords[1] = satmap->y0;
1541
1542 /* insert (x0+width,y0) into position N */
1543 points->coords[718] = satmap->x0 + satmap->width;
1544 points->coords[719] = satmap->y0;
1545 }
1546 else
1547 {
1548 /* insert (x0,y0+height) into position 0 */
1549 points->coords[0] = satmap->x0;
1550 points->coords[1] = satmap->y0 + satmap->height;
1551
1552 /* insert (x0+width,y0+height) into position N */
1553 points->coords[718] = satmap->x0 + satmap->width;
1554 points->coords[719] = satmap->y0 + satmap->height;
1555 }
1556 }
1557
1558 /**
1559 * Sort points according to Y coordinates.
1560 *
1561 * @param satmap The GtkSatMap structure.
1562 * @param sat The satellite data structure.
1563 * @param points The points to sort.
1564 * @param num The number of points. By specifying it as parameter we can
1565 * sort incomplete arrays.
1566 *
1567 * This function sorts the points in ascending order with respect
1568 * to their y value.
1569 */
sort_points_y(GtkSatMap * satmap,sat_t * sat,GooCanvasPoints * points,gint num)1570 static void sort_points_y(GtkSatMap * satmap, sat_t * sat,
1571 GooCanvasPoints * points, gint num)
1572 {
1573 gsize size;
1574
1575 (void)satmap;
1576 (void)sat;
1577 size = 2 * sizeof(double);
1578
1579 /* call g_qsort_with_data, which warps the qsort function
1580 from stdlib */
1581 g_qsort_with_data(points->coords, num, size, compare_coordinates_y, NULL);
1582 }
1583
1584 /**
1585 * Compare two X coordinates.
1586 *
1587 * @param a Pointer to one coordinate (x,y) both double.
1588 * @param b Pointer to the second coordinate (x,y) both double.
1589 * @param data User data; always NULL.
1590 * @return Negative value if a < b; zero if a = b; positive value if a > b.
1591 *
1592 * This function is used by the g_qsort_with_data function to compare two
1593 * elements in the coordinate array of the GooCanvasPoints structure. We have
1594 * to remember that GooCanvasPoints->coords is an array of XY values, i.e.
1595 * [X0,Y0,X1,Y1,...,Xn,Yn], but we only want to sort according to the X
1596 * coordinate. Therefore, we let the g_qsort_with_data believe that the whole
1597 * pair is one element (which is OK even according to the API docs) but we
1598 * cast the pointers to an array with two elements and compare only the first
1599 * one (x).
1600 *
1601 */
compare_coordinates_x(gconstpointer a,gconstpointer b,gpointer data)1602 static gint compare_coordinates_x(gconstpointer a, gconstpointer b,
1603 gpointer data)
1604 {
1605 double *ea = (double *)a;
1606 double *eb = (double *)b;
1607
1608 (void)data;
1609
1610 if (ea[0] < eb[0])
1611 {
1612 return -1;
1613 }
1614 else if (ea[0] > eb[0])
1615 {
1616 return 1;
1617 }
1618
1619 return 0;
1620 }
1621
1622 /**
1623 * Compare two Y coordinates.
1624 *
1625 * @param a Pointer to one coordinate (x,y) both double.
1626 * @param b Pointer to the second coordinate (x,y) both double.
1627 * @param data User data; always NULL.
1628 * @return Negative value if a < b; zero if a = b; positive value if a > b.
1629 *
1630 * This function is used by the g_qsort_with_data function to compare two
1631 * elements in the coordinate array of the GooCanvasPoints structure. We have
1632 * to remember that GooCanvasPoints->coords is an array of XY values, i.e.
1633 * [X0,Y0,X1,Y1,...,Xn,Yn], but we only want to sort according to the Y
1634 * coordinate. Therefore, we let the g_qsort_with_data believe that the whole
1635 * pair is one element (which is OK even according to the API docs) but we
1636 * cast the pointers to an array with two elements and compare only the second
1637 * one (y).
1638 *
1639 */
compare_coordinates_y(gconstpointer a,gconstpointer b,gpointer data)1640 static gint compare_coordinates_y(gconstpointer a, gconstpointer b,
1641 gpointer data)
1642 {
1643 double *ea = (double *)a;
1644 double *eb = (double *)b;
1645
1646 (void)data;
1647
1648 if (ea[1] < eb[1])
1649 {
1650 return -1;
1651 }
1652
1653 else if (ea[1] > eb[1])
1654 {
1655 return 1;
1656 }
1657
1658 return 0;
1659 }
1660
1661 /**
1662 * Plot a satellite.
1663 *
1664 * @param key The hash table key.
1665 * @param value Pointer to the satellite.
1666 * @param data Pointer to the GtkSatMap widget.
1667 *
1668 * This function creates and initializes the canvas objects (rectangle, label,
1669 * footprint) for a satellite. The function is called as a g_hash_table_foreach
1670 * callback.
1671 */
plot_sat(gpointer key,gpointer value,gpointer data)1672 static void plot_sat(gpointer key, gpointer value, gpointer data)
1673 {
1674 GtkSatMap *satmap = GTK_SAT_MAP(data);
1675 sat_map_obj_t *obj = NULL;
1676 sat_t *sat = SAT(value);
1677 GooCanvasItemModel *root;
1678 gint *catnum;
1679 guint32 col, covcol, shadowcol;
1680 gfloat x, y;
1681 gchar *tooltip;
1682
1683 (void)key;
1684
1685 if (decayed(sat))
1686 {
1687 return;
1688 }
1689 /* get satellite and SSP */
1690 catnum = g_new0(gint, 1);
1691 *catnum = sat->tle.catnr;
1692
1693 lonlat_to_xy(satmap, sat->ssplon, sat->ssplat, &x, &y);
1694
1695 /* create and initialize a sat object */
1696 obj = g_try_new(sat_map_obj_t, 1);
1697
1698 if (obj == NULL)
1699 {
1700 sat_log_log(SAT_LOG_LEVEL_ERROR,
1701 _("%s: Cannot allocate memory for satellite %d."),
1702 __func__, sat->tle.catnr);
1703 return;
1704 }
1705
1706 obj->selected = FALSE;
1707
1708 if (!g_hash_table_lookup_extended(satmap->showtracks, catnum, NULL, NULL))
1709 {
1710 obj->showtrack = FALSE;
1711 }
1712 else
1713 {
1714 obj->showtrack = TRUE;
1715 }
1716
1717 if (!g_hash_table_lookup_extended(satmap->hidecovs, catnum, NULL, NULL))
1718 {
1719 obj->showcov = TRUE;
1720 }
1721 else
1722 {
1723 obj->showcov = FALSE;
1724 }
1725 obj->istarget = FALSE;
1726 obj->oldrcnum = 0;
1727 obj->newrcnum = 0;
1728 obj->track_data.latlon = NULL;
1729 obj->track_data.lines = NULL;
1730 obj->track_orbit = 0;
1731
1732 root = goo_canvas_get_root_item_model(GOO_CANVAS(satmap->canvas));
1733
1734 /* satellite color */
1735 col = mod_cfg_get_int(satmap->cfgdata,
1736 MOD_CFG_MAP_SECTION,
1737 MOD_CFG_MAP_SAT_COL, SAT_CFG_INT_MAP_SAT_COL);
1738
1739 /* area coverage colour */
1740 covcol = mod_cfg_get_int(satmap->cfgdata,
1741 MOD_CFG_MAP_SECTION,
1742 MOD_CFG_MAP_SAT_COV_COL,
1743 SAT_CFG_INT_MAP_SAT_COV_COL);
1744 /* coverage color */
1745 if (obj->showcov)
1746 {
1747 covcol = mod_cfg_get_int(satmap->cfgdata,
1748 MOD_CFG_MAP_SECTION,
1749 MOD_CFG_MAP_SAT_COV_COL,
1750 SAT_CFG_INT_MAP_SAT_COV_COL);
1751 }
1752 else
1753 {
1754 covcol = 0x00000000;
1755 }
1756
1757
1758 /* shadow colour (only alpha channel) */
1759 shadowcol = mod_cfg_get_int(satmap->cfgdata,
1760 MOD_CFG_MAP_SECTION,
1761 MOD_CFG_MAP_SHADOW_ALPHA,
1762 SAT_CFG_INT_MAP_SHADOW_ALPHA);
1763
1764 /* create tooltip */
1765 tooltip = g_markup_printf_escaped("<b>%s</b>\n"
1766 "Lon: %5.1f\302\260\n"
1767 "Lat: %5.1f\302\260\n"
1768 " Az: %5.1f\302\260\n"
1769 " El: %5.1f\302\260",
1770 sat->nickname,
1771 sat->ssplon, sat->ssplat,
1772 sat->az, sat->el);
1773
1774 /* create satellite marker and label + shadows. We create shadows first */
1775 obj->shadowm = goo_canvas_rect_model_new(root,
1776 x - MARKER_SIZE_HALF + 1,
1777 y - MARKER_SIZE_HALF + 1,
1778 2 * MARKER_SIZE_HALF,
1779 2 * MARKER_SIZE_HALF,
1780 "fill-color-rgba", 0x00,
1781 "stroke-color-rgba", shadowcol,
1782 NULL);
1783 obj->marker = goo_canvas_rect_model_new(root,
1784 x - MARKER_SIZE_HALF,
1785 y - MARKER_SIZE_HALF,
1786 2 * MARKER_SIZE_HALF,
1787 2 * MARKER_SIZE_HALF,
1788 "fill-color-rgba", col,
1789 "stroke-color-rgba", col,
1790 "tooltip", tooltip, NULL);
1791
1792 obj->shadowl = goo_canvas_text_model_new(root, sat->nickname,
1793 x + 1,
1794 y + 3,
1795 -1,
1796 GOO_CANVAS_ANCHOR_NORTH,
1797 "font", "Sans 8",
1798 "fill-color-rgba", shadowcol,
1799 NULL);
1800 obj->label = goo_canvas_text_model_new(root, sat->nickname,
1801 x,
1802 y + 2,
1803 -1,
1804 GOO_CANVAS_ANCHOR_NORTH,
1805 "font", "Sans 8",
1806 "fill-color-rgba", col,
1807 "tooltip", tooltip, NULL);
1808
1809 g_free(tooltip);
1810
1811 g_object_set_data(G_OBJECT(obj->marker), "catnum",
1812 GINT_TO_POINTER(*catnum));
1813 g_object_set_data(G_OBJECT(obj->label), "catnum",
1814 GINT_TO_POINTER(*catnum));
1815
1816 /* initialize points for footprint */
1817 points1 = goo_canvas_points_new(360);
1818 points2 = goo_canvas_points_new(360);
1819
1820 /* calculate footprint */
1821 obj->newrcnum = calculate_footprint(satmap, sat);
1822 obj->oldrcnum = obj->newrcnum;
1823
1824 /* invisible footprint for decayed sats (STS fix) */
1825 /* if (sat->otype == ORBIT_TYPE_DECAYED) { */
1826 /* col = 0x00000000; */
1827 /* } */
1828
1829 /* always create first part of range circle */
1830 obj->range1 = goo_canvas_polyline_model_new(root, FALSE, 0,
1831 "points", points1,
1832 "line-width", 1.0,
1833 "fill-color-rgba", covcol,
1834 "stroke-color-rgba", col,
1835 "line-cap",
1836 CAIRO_LINE_CAP_SQUARE,
1837 "line-join",
1838 CAIRO_LINE_JOIN_MITER, NULL);
1839 g_object_set_data(G_OBJECT(obj->range1), "catnum",
1840 GINT_TO_POINTER(*catnum));
1841
1842 /* create second part if available */
1843 if (obj->newrcnum == 2)
1844 {
1845 //g_print ("N1:%d N2:%d\n", points1->num_points, points2->num_points);
1846
1847 obj->range2 = goo_canvas_polyline_model_new(root, FALSE, 0,
1848 "points", points2,
1849 "line-width", 1.0,
1850 "fill-color-rgba", covcol,
1851 "stroke-color-rgba", col,
1852 "line-cap",
1853 CAIRO_LINE_CAP_SQUARE,
1854 "line-join",
1855 CAIRO_LINE_JOIN_MITER,
1856 NULL);
1857 g_object_set_data(G_OBJECT(obj->range2), "catnum",
1858 GINT_TO_POINTER(*catnum));
1859
1860 }
1861
1862 goo_canvas_points_unref(points1);
1863 goo_canvas_points_unref(points2);
1864
1865 /* add sat to hash table */
1866 g_hash_table_insert(satmap->obj, catnum, obj);
1867 }
1868
1869 /** Update a given satellite. */
update_sat(gpointer key,gpointer value,gpointer data)1870 static void update_sat(gpointer key, gpointer value, gpointer data)
1871 {
1872 gint *catnum;
1873 GtkSatMap *satmap = GTK_SAT_MAP(data);
1874 sat_map_obj_t *obj = NULL;
1875 sat_t *sat = SAT(value);
1876 gfloat x, y;
1877 gdouble oldx, oldy;
1878 gdouble now; // = get_current_daynum ();
1879 GooCanvasItemModel *root;
1880 gint idx;
1881 guint32 col, covcol;
1882 gchar *tooltip;
1883 gchar *aosstr;
1884
1885 //gdouble sspla,ssplo;
1886
1887 root = goo_canvas_get_root_item_model(GOO_CANVAS(satmap->canvas));
1888
1889 catnum = g_new0(gint, 1);
1890 *catnum = sat->tle.catnr;
1891
1892 now = satmap->tstamp;
1893
1894 /* update next AOS */
1895 if (sat->aos > now)
1896 {
1897 if ((sat->aos < satmap->naos) || (satmap->naos == 0.0))
1898 {
1899 satmap->naos = sat->aos;
1900 satmap->ncat = sat->tle.catnr;
1901 }
1902 }
1903
1904 obj = SAT_MAP_OBJ(g_hash_table_lookup(satmap->obj, catnum));
1905
1906 /* get rid of a decayed satellite */
1907 if (decayed(sat) && obj != NULL)
1908 {
1909 idx = goo_canvas_item_model_find_child(root, obj->marker);
1910 if (idx != -1)
1911 goo_canvas_item_model_remove_child(root, idx);;
1912 idx = goo_canvas_item_model_find_child(root, obj->shadowm);
1913 if (idx != -1)
1914 goo_canvas_item_model_remove_child(root, idx);;
1915 idx = goo_canvas_item_model_find_child(root, obj->label);
1916 if (idx != -1)
1917 goo_canvas_item_model_remove_child(root, idx);
1918 idx = goo_canvas_item_model_find_child(root, obj->shadowl);
1919 if (idx != -1)
1920 goo_canvas_item_model_remove_child(root, idx);
1921 idx = goo_canvas_item_model_find_child(root, obj->range1);
1922 if (idx != -1)
1923 goo_canvas_item_model_remove_child(root, idx);
1924 idx = goo_canvas_item_model_find_child(root, obj->range2);
1925 if (idx != -1)
1926 goo_canvas_item_model_remove_child(root, idx);
1927 g_hash_table_remove(satmap->obj, catnum);
1928 if (obj->showtrack)
1929 ground_track_update(satmap, sat, satmap->qth, obj, TRUE);
1930 g_free(obj);
1931
1932 g_hash_table_remove(satmap->obj, catnum);
1933 return;
1934 }
1935
1936 if (obj == NULL)
1937 {
1938 if (decayed(sat))
1939 {
1940 return;
1941 }
1942 else
1943 {
1944 /* satellite was decayed now is visible
1945 time controller backed up time */
1946 plot_sat(key, value, data);
1947 return;
1948 }
1949 }
1950
1951 if (obj->selected)
1952 {
1953 /* update satmap->sel */
1954 update_selected(satmap, sat);
1955 }
1956
1957 g_object_set(obj->label, "text", sat->nickname, NULL);
1958 g_object_set(obj->shadowl, "text", sat->nickname, NULL);
1959
1960 aosstr = aoslos_time_to_str(satmap, sat);
1961 tooltip = g_markup_printf_escaped("<b>%s</b>\n"
1962 "Lon: %5.1f\302\260\n"
1963 "Lat: %5.1f\302\260\n"
1964 " Az: %5.1f\302\260\n"
1965 " El: %5.1f\302\260\n"
1966 "%s",
1967 sat->nickname,
1968 sat->ssplon, sat->ssplat,
1969 sat->az, sat->el, aosstr);
1970 g_object_set(obj->marker, "tooltip", tooltip, NULL);
1971 g_object_set(obj->label, "tooltip", tooltip, NULL);
1972 g_free(tooltip);
1973 g_free(aosstr);
1974
1975 lonlat_to_xy(satmap, sat->ssplon, sat->ssplat, &x, &y);
1976
1977 /* update only if satellite has moved at least
1978 2 * MARKER_SIZE_HALF (no need to drain CPU all the time)
1979 */
1980 g_object_get(obj->marker, "x", &oldx, "y", &oldy, NULL);
1981
1982 if ((fabs(oldx - x) >= 2 * MARKER_SIZE_HALF) ||
1983 (fabs(oldy - y) >= 2 * MARKER_SIZE_HALF))
1984 {
1985 g_object_set(obj->marker,
1986 "x", (gdouble) (x - MARKER_SIZE_HALF),
1987 "y", (gdouble) (y - MARKER_SIZE_HALF), NULL);
1988 g_object_set(obj->shadowm,
1989 "x", (gdouble) (x - MARKER_SIZE_HALF + 1),
1990 "y", (gdouble) (y - MARKER_SIZE_HALF + 1), NULL);
1991
1992 if (x < 50)
1993 {
1994 g_object_set(obj->label,
1995 "x", (gdouble) (x + 3),
1996 "y", (gdouble) (y), "anchor", GOO_CANVAS_ANCHOR_WEST,
1997 NULL);
1998 g_object_set(obj->shadowl, "x", (gdouble) (x + 3 + 1), "y",
1999 (gdouble) (y + 1), "anchor", GOO_CANVAS_ANCHOR_WEST,
2000 NULL);
2001 }
2002 else if ((satmap->width - x) < 50)
2003 {
2004 g_object_set(obj->label,
2005 "x", (gdouble) (x - 3),
2006 "y", (gdouble) (y), "anchor", GOO_CANVAS_ANCHOR_EAST,
2007 NULL);
2008 g_object_set(obj->shadowl, "x", (gdouble) (x - 3 + 1), "y",
2009 (gdouble) (y + 1), "anchor", GOO_CANVAS_ANCHOR_EAST,
2010 NULL);
2011 }
2012 else if ((satmap->height - y) < 25)
2013 {
2014 g_object_set(obj->label,
2015 "x", (gdouble) (x),
2016 "y", (gdouble) (y - 2),
2017 "anchor", GOO_CANVAS_ANCHOR_SOUTH, NULL);
2018 g_object_set(obj->shadowl,
2019 "x", (gdouble) (x + 1),
2020 "y", (gdouble) (y - 2 + 1),
2021 "anchor", GOO_CANVAS_ANCHOR_SOUTH, NULL);
2022 }
2023 else
2024 {
2025 g_object_set(obj->label,
2026 "x", (gdouble) (x),
2027 "y", (gdouble) (y + 2),
2028 "anchor", GOO_CANVAS_ANCHOR_NORTH, NULL);
2029 g_object_set(obj->shadowl,
2030 "x", (gdouble) (x + 1),
2031 "y", (gdouble) (y + 2 + 1),
2032 "anchor", GOO_CANVAS_ANCHOR_NORTH, NULL);
2033 }
2034
2035 /* initialize points for footprint */
2036 points1 = goo_canvas_points_new(360);
2037 points2 = goo_canvas_points_new(360);
2038
2039 /* calculate footprint */
2040 obj->newrcnum = calculate_footprint(satmap, sat);
2041
2042 /* always update first part */
2043 g_object_set(obj->range1, "points", points1, NULL);
2044
2045 if (obj->newrcnum == 2)
2046 {
2047 if (obj->oldrcnum == 1)
2048 {
2049 /* we need to create the second part */
2050 if (obj->selected)
2051 {
2052 col = mod_cfg_get_int(satmap->cfgdata,
2053 MOD_CFG_MAP_SECTION,
2054 MOD_CFG_MAP_SAT_SEL_COL,
2055 SAT_CFG_INT_MAP_SAT_SEL_COL);
2056 }
2057 else
2058 {
2059 col = mod_cfg_get_int(satmap->cfgdata,
2060 MOD_CFG_MAP_SECTION,
2061 MOD_CFG_MAP_SAT_COL,
2062 SAT_CFG_INT_MAP_SAT_COL);
2063 }
2064 /* coverage color */
2065 if (obj->showcov)
2066 {
2067 covcol = mod_cfg_get_int(satmap->cfgdata,
2068 MOD_CFG_MAP_SECTION,
2069 MOD_CFG_MAP_SAT_COV_COL,
2070 SAT_CFG_INT_MAP_SAT_COV_COL);
2071 }
2072 else
2073 {
2074 covcol = 0x00000000;
2075 }
2076 obj->range2 = goo_canvas_polyline_model_new(root, FALSE, 0,
2077 "points", points2,
2078 "line-width", 1.0,
2079 "fill-color-rgba",
2080 covcol,
2081 "stroke-color-rgba",
2082 col, "line-cap",
2083 CAIRO_LINE_CAP_SQUARE,
2084 "line-join",
2085 CAIRO_LINE_JOIN_MITER,
2086 NULL);
2087 g_object_set_data(G_OBJECT(obj->range2), "catnum",
2088 GINT_TO_POINTER(*catnum));
2089 }
2090 else
2091 {
2092 /* just update the second part */
2093 g_object_set(obj->range2, "points", points2, NULL);
2094 }
2095 }
2096 else
2097 {
2098 if (obj->oldrcnum == 2)
2099 {
2100 /* remove second part */
2101 idx = goo_canvas_item_model_find_child(root, obj->range2);
2102 if (idx != -1)
2103 {
2104 goo_canvas_item_model_remove_child(root, idx);
2105 }
2106 }
2107 }
2108
2109 /* update rc-number */
2110 obj->oldrcnum = obj->newrcnum;
2111
2112 goo_canvas_points_unref(points1);
2113 goo_canvas_points_unref(points2);
2114 }
2115
2116 /* if ground track is visible check whether we have passed into a
2117 new orbit, in which case we need to recalculate the ground track
2118 */
2119 if (obj->showtrack)
2120 {
2121 if (obj->track_orbit != sat->orbit)
2122 {
2123 ground_track_update(satmap, sat, satmap->qth, obj, TRUE);
2124 }
2125 /* otherwise we may be in a map rescale process */
2126 else if (satmap->resize)
2127 {
2128 ground_track_update(satmap, sat, satmap->qth, obj, FALSE);
2129 }
2130 }
2131
2132 g_free(catnum);
2133 }
2134
2135 /**
2136 * Update information about the selected satellite.
2137 *
2138 * @param satmap Pointer to the GtkSatMap widget.
2139 * @param sat Pointer to the selected satellite
2140 */
update_selected(GtkSatMap * satmap,sat_t * sat)2141 static void update_selected(GtkSatMap * satmap, sat_t * sat)
2142 {
2143 guint h, m, s;
2144 gchar *ch, *cm, *cs;
2145 gchar *alsstr, *text;
2146 gdouble number, now;
2147 gboolean isgeo = FALSE; /* set to TRUE if satellite appears to be GEO */
2148
2149 now = satmap->tstamp; //get_current_daynum ();
2150
2151 if (sat->el > 0.0)
2152 {
2153 if (sat->los > 0.0)
2154 {
2155 number = sat->los - now;
2156 alsstr = g_strdup("LOS");
2157 }
2158 else
2159 {
2160 isgeo = TRUE;
2161 }
2162 }
2163 else
2164 {
2165 if (sat->aos > 0.0)
2166 {
2167 number = sat->aos - now;
2168 alsstr = g_strdup("AOS");
2169 }
2170 else
2171 {
2172 isgeo = TRUE;
2173 }
2174 }
2175
2176 /* if satellite appears to be GEO don't attempt to show AOS/LOS */
2177 if (isgeo)
2178 {
2179 if (sat->el > 0.0)
2180 {
2181 text =
2182 g_markup_printf_escaped
2183 ("<span background=\"#%s\"> %s: Always in range </span>",
2184 satmap->infobgd, sat->nickname);
2185 }
2186 else
2187 {
2188 text =
2189 g_markup_printf_escaped
2190 ("<span background=\"#%s\"> %s: Always out of range </span>",
2191 satmap->infobgd, sat->nickname);
2192 }
2193 }
2194 else
2195 {
2196 /* convert julian date to seconds */
2197 s = (guint) (number * 86400);
2198
2199 /* extract hours */
2200 h = (guint) floor(s / 3600);
2201 s -= 3600 * h;
2202
2203 /* leading zero */
2204 if ((h > 0) && (h < 10))
2205 ch = g_strdup("0");
2206 else
2207 ch = g_strdup("");
2208
2209 /* extract minutes */
2210 m = (guint) floor(s / 60);
2211 s -= 60 * m;
2212
2213 /* leading zero */
2214 if (m < 10)
2215 cm = g_strdup("0");
2216 else
2217 cm = g_strdup("");
2218
2219 /* leading zero */
2220 if (s < 10)
2221 cs = g_strdup(":0");
2222 else
2223 cs = g_strdup(":");
2224
2225 if (h > 0)
2226 {
2227 text = g_markup_printf_escaped("<span background=\"#%s\"> "
2228 "%s %s in %s%d:%s%d%s%d </span>",
2229 satmap->infobgd, sat->nickname,
2230 alsstr, ch, h, cm, m, cs, s);
2231 }
2232 else
2233 {
2234 text = g_markup_printf_escaped("<span background=\"#%s\"> "
2235 "%s %s in %s%d%s%d </span>",
2236 satmap->infobgd, sat->nickname,
2237 alsstr, cm, m, cs, s);
2238 }
2239
2240 g_free(ch);
2241 g_free(cm);
2242 g_free(cs);
2243 g_free(alsstr);
2244 }
2245
2246 /* update info text */
2247 g_object_set(satmap->sel, "text", text, NULL);
2248 g_free(text);
2249 }
2250
draw_grid_lines(GtkSatMap * satmap,GooCanvasItemModel * root)2251 static void draw_grid_lines(GtkSatMap * satmap, GooCanvasItemModel * root)
2252 {
2253 gdouble xstep, ystep;
2254 gfloat lon, lat;
2255 guint32 col;
2256 guint i;
2257 gchar *buf, hmf = ' ';
2258
2259 /* initialize algo parameters */
2260 col = mod_cfg_get_int(satmap->cfgdata,
2261 MOD_CFG_MAP_SECTION,
2262 MOD_CFG_MAP_GRID_COL, SAT_CFG_INT_MAP_GRID_COL);
2263
2264 xstep = (gdouble) (30.0 * satmap->width / 360.0);
2265 ystep = (gdouble) (30.0 * satmap->height / 180.0);
2266
2267 #define MKLINE goo_canvas_polyline_model_new_line
2268
2269 /* horizontal grid */
2270 for (i = 0; i < 5; i++)
2271 {
2272 /* line */
2273 satmap->gridh[i] = MKLINE(root,
2274 (gdouble) satmap->x0,
2275 (gdouble) (satmap->y0 + (i + 1) * ystep),
2276 (gdouble) (satmap->x0 + satmap->width),
2277 (gdouble) (satmap->y0 + (i + 1) * ystep),
2278 "stroke-color-rgba", col,
2279 "line-cap", CAIRO_LINE_CAP_SQUARE,
2280 "line-join", CAIRO_LINE_JOIN_MITER,
2281 "line-width", 0.5, NULL);
2282
2283 /* FIXME: Use dotted line pattern? */
2284
2285 /* label */
2286 xy_to_lonlat(satmap, satmap->x0, satmap->y0 + (i + 1) * ystep, &lon,
2287 &lat);
2288 if (sat_cfg_get_bool(SAT_CFG_BOOL_USE_NSEW))
2289 {
2290 if (lat < 0.00)
2291 {
2292 lat = -lat;
2293 hmf = 'S';
2294 }
2295 else
2296 {
2297 hmf = 'N';
2298 }
2299 }
2300 buf = g_strdup_printf("%.0f\302\260%c", lat, hmf);
2301 satmap->gridhlab[i] = goo_canvas_text_model_new(root,
2302 buf,
2303 (gdouble) (satmap->x0 +
2304 15),
2305 (gdouble) (satmap->y0 +
2306 (i +
2307 1) *
2308 ystep), -1,
2309 GOO_CANVAS_ANCHOR_NORTH,
2310 "font", "Sans 8",
2311 "fill-color-rgba", col,
2312 NULL);
2313 g_free(buf);
2314
2315 /* lower items to be just above the background map
2316 or below it if lines are invisible
2317 */
2318 if (satmap->showgrid)
2319 {
2320 goo_canvas_item_model_raise(satmap->gridh[i], satmap->map);
2321 goo_canvas_item_model_raise(satmap->gridhlab[i], satmap->map);
2322 }
2323 else
2324 {
2325 goo_canvas_item_model_lower(satmap->gridh[i], satmap->map);
2326 goo_canvas_item_model_lower(satmap->gridhlab[i], satmap->map);
2327 }
2328 }
2329
2330 /* vertical grid */
2331 for (i = 0; i < 11; i++)
2332 {
2333 /* line */
2334 satmap->gridv[i] = MKLINE(root,
2335 (gdouble) (satmap->x0 + (i + 1) * xstep),
2336 (gdouble) satmap->y0,
2337 (gdouble) (satmap->x0 + (i + 1) * xstep),
2338 (gdouble) (satmap->y0 + satmap->height),
2339 "stroke-color-rgba", col,
2340 "line-cap", CAIRO_LINE_CAP_SQUARE,
2341 "line-join", CAIRO_LINE_JOIN_MITER,
2342 "line-width", 0.5, NULL);
2343
2344 /* label */
2345 xy_to_lonlat(satmap, satmap->x0 + (i + 1) * xstep, satmap->y0, &lon,
2346 &lat);
2347 if (sat_cfg_get_bool(SAT_CFG_BOOL_USE_NSEW))
2348 {
2349 if (lon < 0.00)
2350 {
2351 lon = -lon;
2352 hmf = 'W';
2353 }
2354 else
2355 {
2356 hmf = 'E';
2357 }
2358 }
2359 buf = g_strdup_printf("%.0f\302\260%c", lon, hmf);
2360 satmap->gridvlab[i] = goo_canvas_text_model_new(root,
2361 buf,
2362 (gdouble) (satmap->x0 +
2363 (i +
2364 1) *
2365 xstep),
2366 (gdouble) (satmap->y0 +
2367 satmap->height
2368 - 5), -1,
2369 GOO_CANVAS_ANCHOR_EAST,
2370 "font", "Sans 8",
2371 "fill-color-rgba", col,
2372 NULL);
2373 g_free(buf);
2374
2375 /* lower items to be just above the background map
2376 or below it if lines are invisible
2377 */
2378 if (satmap->showgrid)
2379 {
2380 goo_canvas_item_model_raise(satmap->gridv[i], satmap->map);
2381 goo_canvas_item_model_raise(satmap->gridvlab[i], satmap->map);
2382 }
2383 else
2384 {
2385 goo_canvas_item_model_lower(satmap->gridv[i], satmap->map);
2386 goo_canvas_item_model_lower(satmap->gridvlab[i], satmap->map);
2387 }
2388 }
2389 }
2390
draw_terminator(GtkSatMap * satmap,GooCanvasItemModel * root)2391 static void draw_terminator(GtkSatMap * satmap, GooCanvasItemModel * root)
2392 {
2393 guint32 terminator_col;
2394 guint32 globe_shadow_col;
2395
2396 /* initialize algo parameters */
2397 terminator_col = mod_cfg_get_int(satmap->cfgdata,
2398 MOD_CFG_MAP_SECTION,
2399 MOD_CFG_MAP_TERMINATOR_COL,
2400 SAT_CFG_INT_MAP_TERMINATOR_COL);
2401
2402 globe_shadow_col = mod_cfg_get_int(satmap->cfgdata,
2403 MOD_CFG_MAP_SECTION,
2404 MOD_CFG_MAP_GLOBAL_SHADOW_COL,
2405 SAT_CFG_INT_MAP_GLOBAL_SHADOW_COL);
2406
2407 /* We do not set any polygon vertices here, but trust that the redraw_terminator
2408 will be called in due course to do the job. */
2409
2410 satmap->terminator = goo_canvas_polyline_model_new(root, FALSE, 0,
2411 "line-width", 1.0,
2412 "fill-color-rgba",
2413 globe_shadow_col,
2414 "stroke-color-rgba",
2415 terminator_col,
2416 "line-cap",
2417 CAIRO_LINE_CAP_SQUARE,
2418 "line-join",
2419 CAIRO_LINE_JOIN_MITER,
2420 NULL);
2421
2422 goo_canvas_item_model_raise(satmap->terminator, satmap->map);
2423
2424 satmap->terminator_last_tstamp = satmap->tstamp;
2425 }
2426
redraw_grid_lines(GtkSatMap * satmap)2427 static void redraw_grid_lines(GtkSatMap * satmap)
2428 {
2429 GooCanvasPoints *line;
2430 gdouble xstep, ystep;
2431 guint i;
2432
2433 xstep = (gdouble) 30.0 *((gdouble) satmap->width) / 360.0;
2434 ystep = (gdouble) 30.0 *((gdouble) satmap->height) / 180.0;
2435
2436 /* horizontal grid */
2437 for (i = 0; i < 5; i++)
2438 {
2439
2440 /* update line */
2441 line = goo_canvas_points_new(2);
2442 line->coords[0] = (gdouble) satmap->x0;
2443 line->coords[1] = (gdouble) (satmap->y0 + (i + 1) * ystep);
2444 line->coords[2] = (gdouble) (satmap->x0 + satmap->width);
2445 line->coords[3] = (gdouble) (satmap->y0 + (i + 1) * ystep);
2446 g_object_set(satmap->gridh[i], "points", line, NULL);
2447 goo_canvas_points_unref(line);
2448
2449 /* update label */
2450 g_object_set(satmap->gridhlab[i],
2451 "x", (gdouble) (satmap->x0 + 15),
2452 "y", (gdouble) (satmap->y0 + (i + 1) * ystep), NULL);
2453
2454 /* lower items to be just above the background map
2455 or below it if lines are invisible
2456 */
2457 if (satmap->showgrid)
2458 {
2459 goo_canvas_item_model_raise(satmap->gridh[i], satmap->map);
2460 goo_canvas_item_model_raise(satmap->gridhlab[i], satmap->map);
2461 }
2462 else
2463 goo_canvas_item_model_lower(satmap->gridh[i], satmap->map);
2464 }
2465
2466 /* vertical grid */
2467 for (i = 0; i < 11; i++)
2468 {
2469 /* update line */
2470 line = goo_canvas_points_new(2);
2471 line->coords[0] = (gdouble) (satmap->x0 + (i + 1) * xstep);
2472 line->coords[1] = (gdouble) satmap->y0;
2473 line->coords[2] = (gdouble) (satmap->x0 + (i + 1) * xstep);
2474 line->coords[3] = (gdouble) (satmap->y0 + satmap->height);
2475 g_object_set(satmap->gridv[i], "points", line, NULL);
2476 goo_canvas_points_unref(line);
2477
2478 /* update label */
2479 g_object_set(satmap->gridvlab[i],
2480 "x", (gdouble) (satmap->x0 + (i + 1) * xstep),
2481 "y", (gdouble) (satmap->y0 + satmap->height - 5), NULL);
2482
2483 /* lower items to be just above the background map
2484 or below it if lines are invisible
2485 */
2486 if (satmap->showgrid)
2487 {
2488 goo_canvas_item_model_raise(satmap->gridv[i], satmap->map);
2489 goo_canvas_item_model_raise(satmap->gridvlab[i], satmap->map);
2490 }
2491 else
2492 {
2493 goo_canvas_item_model_lower(satmap->gridv[i], satmap->map);
2494 goo_canvas_item_model_lower(satmap->gridvlab[i], satmap->map);
2495 }
2496 }
2497 }
2498
sgn(gdouble const t)2499 static inline gdouble sgn(gdouble const t)
2500 {
2501 return t < 0.0 ? -1.0 : 1.0;
2502 }
2503
redraw_terminator(GtkSatMap * satmap)2504 static void redraw_terminator(GtkSatMap * satmap)
2505 {
2506 /* Set of (x, y) points along the terminator, one on each line of longitude in
2507 increments of longitudinal degrees. */
2508 GooCanvasPoints *line;
2509
2510 /* A variable which iterates over the longitudes. */
2511 int longitude;
2512
2513 /* Working variables in the computation of the terminator coordinates. */
2514 gfloat x, y;
2515
2516 /* Vector normal to plane containing a line of longitude (z component is
2517 always zero). */
2518 /* Note: our coordinates have z along the Earth's axis, x pointing through the
2519 intersection of the Greenwich Meridian and the Equator, and y right-handedly
2520 perpendicular to both. */
2521 gdouble lx, ly;
2522
2523 /* The position of the sun as latitude, longitude. */
2524 geodetic_t geodetic;
2525
2526 /* Vector which points from the centre of the Earth to the Sun in inertial
2527 coordinates. */
2528 vector_t sun_;
2529
2530 /* The same vector in geodesic coordinates. */
2531 gdouble sx, sy, sz;
2532
2533 /* Vector cross-product of (lx,ly,lz) and sun vector. */
2534 gdouble rx, ry, rz;
2535
2536 line = goo_canvas_points_new(363);
2537
2538 Calculate_Solar_Position(satmap->tstamp, &sun_);
2539 Calculate_LatLonAlt(satmap->tstamp, &sun_, &geodetic);
2540
2541 sx = cos(geodetic.lat) * cos(geodetic.lon);
2542 sy = cos(geodetic.lat) * sin(-geodetic.lon);
2543 sz = sin(geodetic.lat);
2544
2545
2546 for (longitude = -180; longitude <= 180; ++longitude)
2547 {
2548
2549 lx = cos(de2ra * (longitude + sgn(sz) * 90));
2550 ly = sin(de2ra * (longitude + sgn(sz) * 90));
2551 /* lz = 0.0; */
2552
2553 rx = ly * sz /* -lz*sy */ ;
2554 ry = /* lz*sx */ -lx * sz;
2555 rz = -lx * sy - ly * sx;
2556
2557 gdouble length = sqrt(rx * rx + ry * ry + rz * rz);
2558
2559 lonlat_to_xy(satmap,
2560 longitude, asin(rz / length) * (1.0 / de2ra), &x, &y);
2561
2562 line->coords[2 * (longitude + 181)] = x;
2563 line->coords[2 * (longitude + 181) + 1] = y;
2564 }
2565
2566 lonlat_to_xy(satmap, -180.0, sz < 0.0 ? 90.0 : -90.0, &x, &y);
2567 line->coords[0] = x;
2568 line->coords[1] = y;
2569
2570 lonlat_to_xy(satmap, 180.0, sz < 0.0 ? 90.0 : -90.0, &x, &y);
2571 line->coords[724] = x;
2572 line->coords[725] = y;
2573
2574 g_object_set(satmap->terminator, "points", line, NULL);
2575 goo_canvas_points_unref(line);
2576 }
2577
gtk_sat_map_lonlat_to_xy(GtkSatMap * m,gdouble lon,gdouble lat,gdouble * x,gdouble * y)2578 void gtk_sat_map_lonlat_to_xy(GtkSatMap * m,
2579 gdouble lon, gdouble lat,
2580 gdouble * x, gdouble * y)
2581 {
2582 gfloat fx, fy;
2583
2584 fx = (gfloat) * x;
2585 fy = (gfloat) * y;
2586
2587 lonlat_to_xy(m, lon, lat, &fx, &fy);
2588
2589 *x = (gdouble) fx;
2590 *y = (gdouble) fy;
2591 }
2592
gtk_sat_map_reload_sats(GtkWidget * satmap,GHashTable * sats)2593 void gtk_sat_map_reload_sats(GtkWidget * satmap, GHashTable * sats)
2594 {
2595 GTK_SAT_MAP(satmap)->sats = sats;
2596 GTK_SAT_MAP(satmap)->naos = 0.0;
2597 GTK_SAT_MAP(satmap)->ncat = 0;
2598
2599 /* reset ground track orbit to force repaint */
2600 g_hash_table_foreach(GTK_SAT_MAP(satmap)->obj, reset_ground_track, NULL);
2601 }
2602
reset_ground_track(gpointer key,gpointer value,gpointer user_data)2603 static void reset_ground_track(gpointer key, gpointer value,
2604 gpointer user_data)
2605 {
2606 sat_map_obj_t *obj = (sat_map_obj_t *) value;
2607 (void) key;
2608 (void) user_data;
2609
2610 obj->track_orbit = 0;
2611 }
2612
aoslos_time_to_str(GtkSatMap * satmap,sat_t * sat)2613 static gchar *aoslos_time_to_str(GtkSatMap * satmap, sat_t * sat)
2614 {
2615 guint h, m, s;
2616 gdouble number, now;
2617 gchar *text = NULL;
2618
2619
2620 now = satmap->tstamp; //get_current_daynum ();
2621 if (sat->el > 0.0)
2622 {
2623 number = sat->los - now;
2624 }
2625 else
2626 {
2627 number = sat->aos - now;
2628 }
2629
2630 /* convert julian date to seconds */
2631 s = (guint) (number * 86400);
2632
2633 /* extract hours */
2634 h = (guint) floor(s / 3600);
2635 s -= 3600 * h;
2636
2637 /* extract minutes */
2638 m = (guint) floor(s / 60);
2639 s -= 60 * m;
2640
2641 if (sat->el > 0.0)
2642 text = g_strdup_printf(_("LOS in %d minutes"), m + 60 * h);
2643 else
2644 text = g_strdup_printf(_("AOS in %d minutes"), m + 60 * h);
2645
2646 return text;
2647 }
2648
2649 /** Load the satellites that we should show tracks for */
gtk_sat_map_load_showtracks(GtkSatMap * satmap)2650 static void gtk_sat_map_load_showtracks(GtkSatMap * satmap)
2651 {
2652 mod_cfg_get_integer_list_boolean(satmap->cfgdata,
2653 MOD_CFG_MAP_SECTION,
2654 MOD_CFG_MAP_SHOWTRACKS,
2655 satmap->showtracks);
2656
2657 }
2658
2659 /** Save the satellites that we should not show ground tracks */
gtk_sat_map_store_showtracks(GtkSatMap * satmap)2660 static void gtk_sat_map_store_showtracks(GtkSatMap * satmap)
2661 {
2662 mod_cfg_set_integer_list_boolean(satmap->cfgdata,
2663 satmap->showtracks,
2664 MOD_CFG_MAP_SECTION,
2665 MOD_CFG_MAP_SHOWTRACKS);
2666 }
2667
2668 /** Save the satellites that we should not highlight coverage */
gtk_sat_map_store_hidecovs(GtkSatMap * satmap)2669 static void gtk_sat_map_store_hidecovs(GtkSatMap * satmap)
2670 {
2671 mod_cfg_set_integer_list_boolean(satmap->cfgdata,
2672 satmap->hidecovs,
2673 MOD_CFG_MAP_SECTION,
2674 MOD_CFG_MAP_HIDECOVS);
2675 }
2676
2677 /** Load the satellites that we should not highlight coverage */
gtk_sat_map_load_hide_coverages(GtkSatMap * satmap)2678 static void gtk_sat_map_load_hide_coverages(GtkSatMap * satmap)
2679 {
2680 mod_cfg_get_integer_list_boolean(satmap->cfgdata,
2681 MOD_CFG_MAP_SECTION,
2682 MOD_CFG_MAP_HIDECOVS, satmap->hidecovs);
2683 }
2684