/* 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
/* 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;
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] );
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 );
{ "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 ******/
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;
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]);
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) )
if ( t->holding )
{
VikCoord new_coord;
- GdkGC *gc;
vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
/* snap to TP */
}
+/*** 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)
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);
+
+}