]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Using the new icon
[andy/viking.git] / src / viktrwlayer.c
index f5b182b3355305e71a6db9f2f294ceadfee4d9d9..b3d0e1d0cbc7586b76d15931d1e5114d9acf1c90 100644 (file)
@@ -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"
 #include "thumbnails.h"
 #include "background.h"
 #include "gpx.h"
+#include "babel.h"
 
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 
+#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);
+
+}