X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/c75d78d716963e3a6b26f6c0bcec43b8c8ca76ec..020b155be89ee1825309eb6d8d1958f3b46c310d:/src/viktrwlayer.c?ds=inline diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index f5b182b3..b3d0e1d0 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -25,6 +25,7 @@ /* viktrwlayer.c -- 2200 lines can make a difference in the state of things */ #include "viking.h" +#include "vikmapslayer.h" #include "viktrwlayer_pixmap.h" #include "viktrwlayer_tpwin.h" #include "viktrwlayer_propwin.h" @@ -32,12 +33,14 @@ #include "thumbnails.h" #include "background.h" #include "gpx.h" +#include "babel.h" #include #include #include #include +#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%f,%f to %f,%f&output=js\" 2>/dev/null)" #define VIK_TRW_LAYER_TRACK_GC 13 #define VIK_TRW_LAYER_TRACK_GC_RATES 10 #define VIK_TRW_LAYER_TRACK_GC_MIN 0 @@ -121,6 +124,10 @@ struct _VikTrwLayer { /* track editing tool -- more specifically, moving tps */ gboolean moving_tp; + /* magic scissors tool */ + gboolean magic_scissors_started; + VikCoord magic_scissors_coord; + gboolean drawlabels; gboolean drawimages; guint8 image_alpha; @@ -179,6 +186,7 @@ static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] ); static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ); static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ); static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ); +static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]); static void trw_layer_centerize ( gpointer layer_and_vlp[2] ); static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type ); static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ); @@ -227,6 +235,9 @@ static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); + static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str ); @@ -262,6 +273,9 @@ static VikToolInterface trw_layer_tools[] = { { "Show Picture", (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL, (VikToolMouseFunc) tool_show_picture_click, NULL, NULL }, + + { "Magic Scissors", (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL }, }; /****** PARAMETERS ******/ @@ -767,6 +781,9 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode ) rv->current_tp_track_name = NULL; rv->moving_tp = FALSE; rv->moving_wp = FALSE; + + rv->magic_scissors_started = FALSE; + rv->waypoint_rightclick = FALSE; rv->last_tpl = NULL; rv->last_tp_track_name = NULL; @@ -1810,6 +1827,42 @@ gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name return was_visible; } +static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt) +{ + vik_treeview_item_delete (vt, it ); +} + +void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl ) +{ + + vtl->current_track = NULL; + if (vtl->current_tp_track_name) + trw_layer_cancel_current_tp(vtl, FALSE); + if (vtl->last_tp_track_name) + trw_layer_cancel_last_tp ( vtl ); + + g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); + g_hash_table_remove_all(vtl->tracks_iters); + g_hash_table_remove_all(vtl->tracks); + + /* TODO: only update if the layer is visible (ticked) */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) +{ + vtl->current_wp = NULL; + vtl->current_wp_name = NULL; + vtl->moving_wp = FALSE; + + g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); + g_hash_table_remove_all(vtl->waypoints_iters); + g_hash_table_remove_all(vtl->waypoints); + + /* TODO: only update if the layer is visible (ticked) */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + static void trw_layer_delete_item ( gpointer pass_along[5] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); @@ -2380,6 +2433,11 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_label ( "Download maps along track..." ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); } if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) @@ -3052,7 +3110,6 @@ static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *ev if ( t->holding ) { VikCoord new_coord; - GdkGC *gc; vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); /* snap to TP */ @@ -3112,6 +3169,32 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton } +/*** Magic Scissors ***/ +static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + VikCoord tmp; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp ); + if ( vtl->magic_scissors_started ) { + struct LatLon start, end; + gchar *cmd; + vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start ); + vik_coord_to_latlon ( &(tmp), &end ); + cmd = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, start.lat, start.lon, end.lat, end.lon ); + a_babel_convert_from_shellcommand ( vtl, cmd, "google", NULL, NULL ); + g_free ( cmd ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + } else { + vtl->magic_scissors_coord = tmp; + } + vtl->magic_scissors_started = !vtl->magic_scissors_started; + return TRUE; +} + /*** Show picture ****/ static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp) @@ -3266,3 +3349,225 @@ static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl) return(vtl->menu_selection); } +/* ----------- Downloading maps along tracks --------------- */ + +static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh) +{ + /* TODO: calculating based on current size of viewport */ + const gdouble w_at_zoom_0_125 = 0.0013; + const gdouble h_at_zoom_0_125 = 0.0011; + gdouble zoom_factor = zoom_level/0.125; + + wh->lat = h_at_zoom_0_125 * zoom_factor; + wh->lon = w_at_zoom_0_125 * zoom_factor; + + return 0; /* all OK */ +} + +static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient) +{ + if ((dist->lon >= ABS(to->east_west - from->east_west)) && + (dist->lat >= ABS(to->north_south - from->north_south))) + return NULL; + + VikCoord *coord = g_malloc(sizeof(VikCoord)); + coord->mode = VIK_COORD_LATLON; + + if (ABS(gradient) < 1) { + if (from->east_west > to->east_west) + coord->east_west = from->east_west - dist->lon; + else + coord->east_west = from->east_west + dist->lon; + coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south; + } else { + if (from->north_south > to->north_south) + coord->north_south = from->north_south - dist->lat; + else + coord->north_south = from->north_south + dist->lat; + coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south; + } + + return coord; +} + +static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist) +{ + /* TODO: handle virtical track (to->east_west - from->east_west == 0) */ + gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west); + + VikCoord *next = from; + while (TRUE) { + if ((next = get_next_coord(next, to, dist, gradient)) == NULL) + break; + list = g_list_prepend(list, next); + } + + return list; +} + +void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level) +{ + typedef struct _Rect { + VikCoord tl; + VikCoord br; + VikCoord center; + } Rect; +#define GLRECT(iter) ((Rect *)((iter)->data)) + + struct LatLon wh; + GList *rects_to_download = NULL; + GList *rect_iter; + + if (get_download_area_width(vvp, zoom_level, &wh)) + return; + + GList *iter = tr->trackpoints; + if (!iter) + return; + + gboolean new_map = TRUE; + VikCoord *cur_coord, tl, br; + Rect *rect; + while (iter) { + cur_coord = &(VIK_TRACKPOINT(iter->data))->coord; + if (new_map) { + vik_coord_set_area(cur_coord, &wh, &tl, &br); + rect = g_malloc(sizeof(Rect)); + rect->tl = tl; + rect->br = br; + rect->center = *cur_coord; + rects_to_download = g_list_prepend(rects_to_download, rect); + new_map = FALSE; + iter = iter->next; + continue; + } + gboolean found = FALSE; + for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) { + if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) { + found = TRUE; + break; + } + } + if (found) + iter = iter->next; + else + new_map = TRUE; + } + + /* fill-ins for far apart points */ + GList *cur_rect, *next_rect; + GList *fillins = NULL; + for (cur_rect = rects_to_download; + (next_rect = cur_rect->next) != NULL; + cur_rect = cur_rect->next) { + if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) || + (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) { + fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh); + } + } + + if (fillins) { + GList *iter = fillins; + while (iter) { + cur_coord = (VikCoord *)(iter->data); + vik_coord_set_area(cur_coord, &wh, &tl, &br); + rect = g_malloc(sizeof(Rect)); + rect->tl = tl; + rect->br = br; + rect->center = *cur_coord; + rects_to_download = g_list_prepend(rects_to_download, rect); + iter = iter->next; + } + } + + for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) { + maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level); + } + + if (fillins) { + for (iter = fillins; iter; iter = iter->next) + g_free(iter->data); + g_list_free(fillins); + } + if (rects_to_download) { + for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) + g_free(rect_iter->data); + g_list_free(rects_to_download); + } +} + +static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]) +{ + VikMapsLayer *vml; + gint selected_map, default_map; + gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL }; + gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}; + gint selected_zoom, default_zoom; + int i,j; + + + VikTrwLayer *vtl = pass_along[0]; + VikLayersPanel *vlp = pass_along[1]; + VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl))); + + GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS); + int num_maps = g_list_length(vmls); + + if (!num_maps) { + a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR,"No map layer in use. Create one first", NULL); + return; + } + + gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer)); + VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer)); + + gchar **np = map_names; + VikMapsLayer **lp = map_layers; + for (i = 0; i < num_maps; i++) { + gboolean dup = FALSE; + vml = (VikMapsLayer *)(vmls->data); + for (j = 0; j < i; j++) { /* no duplicate allowed */ + if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) { + dup = TRUE; + break; + } + } + if (!dup) { + *lp++ = vml; + *np++ = vik_maps_layer_get_map_label(vml); + } + vmls = vmls->next; + } + *lp = NULL; + *np = NULL; + num_maps = lp - map_layers; + + for (default_map = 0; default_map < num_maps; default_map++) { + /* TODO: check for parent layer's visibility */ + if (VIK_LAYER(map_layers[default_map])->visible) + break; + } + default_map = (default_map == num_maps) ? 0 : default_map; + + gdouble cur_zoom = vik_viewport_get_zoom(vvp); + for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) { + if (cur_zoom == zoom_vals[default_zoom]) + break; + } + default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom; + + if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom)) + goto done; + + vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]); + +done: + for (i = 0; i < num_maps; i++) + g_free(map_names[i]); + g_free(map_names); + g_free(map_layers); + + g_list_free(vmls); + +}