X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/387ff7ac8e96fb90dbfd764956582a499a9bc699..bd78ae7d70bd7388d4950f3e7331b72f84eab208:/src/viktrwlayer.c?ds=sidebyside diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index b741bd42..a5d79e1d 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -56,6 +56,7 @@ #include "datasource_gps.h" #include "vikexttool_datasources.h" #include "util.h" +#include "vikutils.h" #include "vikrouting.h" @@ -459,8 +460,8 @@ enum { /****** PARAMETERS ******/ -static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") }; -enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES }; +static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced") }; +enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV }; static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL }; static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 }; @@ -545,29 +546,27 @@ VikLayerParam trw_layer_params[] = { { VIK_LAYER_TRW, "trackdrawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, N_("Note: the individual track controls what labels may be displayed"), vik_lpd_true_default, NULL, NULL }, - { VIK_LAYER_TRW, "trackfontsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Labels Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, tnfontsize_default, NULL, NULL }, + { VIK_LAYER_TRW, "trackfontsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Labels Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, tnfontsize_default, NULL, NULL }, { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default, NULL, NULL }, - { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default }, { VIK_LAYER_TRW, "trackcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("All Tracks Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, N_("The color used when 'All Tracks Same Color' drawing mode is selected"), black_color_default, NULL, NULL }, { VIK_LAYER_TRW, "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, - { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[0], NULL, NULL, line_thickness_default, NULL, NULL }, + { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[0], NULL, NULL, line_thickness_default, NULL, NULL }, { VIK_LAYER_TRW, "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL }, - { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL }, + { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL }, { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, - { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL }, + { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL }, { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL }, - { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL }, - + { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL }, { VIK_LAYER_TRW, "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, N_("Whether to draw a marker when trackpoints are at the same position but over the minimum stop length apart in time"), vik_lpd_false_default, NULL, NULL }, - { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[8], NULL, NULL, stop_length_default, NULL, NULL }, + { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[8], NULL, NULL, stop_length_default, NULL, NULL }, - { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL }, - { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL }, - { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[1], NULL, + { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL }, + { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS_ADV, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL }, + { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS_ADV, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[1], NULL, N_("The percentage factor away from the average speed determining the color used"), speed_factor_default, NULL, NULL }, - { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL }, + { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL }, { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, { VIK_LAYER_TRW, "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, wpfontsize_default, NULL, NULL }, @@ -2630,52 +2629,30 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g return NULL; } -/* - * Function to show basic track point information on the statusbar +#define VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT "trkpt_selected_statusbar_format" + +/** + * set_statusbar_msg_info_trkpt: + * + * Function to show track point information on the statusbar + * Items displayed is controlled by the settings format code */ static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt ) { - gchar tmp_buf1[64]; - switch (a_vik_get_units_height ()) { - case VIK_UNITS_HEIGHT_FEET: - g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(trkpt->altitude))); - break; - default: - //VIK_UNITS_HEIGHT_METRES: - g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dm"), (int)round(trkpt->altitude)); - } - - gchar tmp_buf2[64]; - tmp_buf2[0] = '\0'; - if ( trkpt->has_timestamp ) { - // Compact date time format - strftime (tmp_buf2, sizeof(tmp_buf2), _(" | Time %x %X"), localtime(&(trkpt->timestamp))); + gchar *statusbar_format_code = NULL; + gboolean need2free = FALSE; + if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) { + // Otherwise use default + statusbar_format_code = g_strdup ( "KATDN" ); + need2free = TRUE; } - // Position part - // Position is put later on, as this bit may not be seen if the display is not big enough, - // one can easily use the current pointer position to see this if needed - gchar *lat = NULL, *lon = NULL; - static struct LatLon ll; - vik_coord_to_latlon (&(trkpt->coord), &ll); - a_coords_latlon_to_string ( &ll, &lat, &lon ); - - // Track name - // Again is put later on, as this bit may not be seen if the display is not big enough - // trackname can be seen from the treeview (when enabled) - // Also name could be very long to not leave room for anything else - gchar tmp_buf3[64]; - tmp_buf3[0] = '\0'; - if ( vtl->current_tp_track ) { - g_snprintf(tmp_buf3, sizeof(tmp_buf3), _(" | Track: %s"), vtl->current_tp_track->name ); - } - - // Combine parts to make overall message - gchar *msg = g_strdup_printf (_("%s%s | %s %s %s"), tmp_buf1, tmp_buf2, lat, lon, tmp_buf3); + gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, NULL, vtl->current_tp_track ); vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg ); - g_free ( lat ); - g_free ( lon ); g_free ( msg ); + + if ( need2free ) + g_free ( statusbar_format_code ); } /* @@ -3247,9 +3224,7 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC wp->coord = *def_coord; // Attempt to auto set height if DEM data is available - gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST ); - if ( elev != VIK_DEM_INVALID_ELEVATION ) - wp->altitude = (gdouble)elev; + vik_waypoint_apply_dem_data ( wp, TRUE ); returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated ); @@ -4611,7 +4586,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) // Get confirmation from the user // Maybe this Waypoint Delete should be optional as is it could get annoying... if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - _("Are you sure you want to delete the waypoint \"%s\""), + _("Are you sure you want to delete the waypoint \"%s\"?"), wp->name ) ) return; was_visible = trw_layer_delete_waypoint ( vtl, wp ); @@ -4624,7 +4599,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) if ( GPOINTER_TO_INT ( pass_along[4]) ) // Get confirmation from the user if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - _("Are you sure you want to delete the track \"%s\""), + _("Are you sure you want to delete the track \"%s\"?"), trk->name ) ) return; was_visible = vik_trw_layer_delete_track ( vtl, trk ); @@ -4637,7 +4612,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) if ( GPOINTER_TO_INT ( pass_along[4]) ) // Get confirmation from the user if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - _("Are you sure you want to delete the route \"%s\""), + _("Are you sure you want to delete the route \"%s\"?"), trk->name ) ) return; was_visible = vik_trw_layer_delete_route ( vtl, trk ); @@ -4708,11 +4683,39 @@ static void trw_layer_properties_item ( gpointer pass_along[7] ) tr, pass_along[1], /* vlp */ pass_along[5], /* vvp */ - pass_along[6]); /* iter */ + pass_along[6], /* iter */ + FALSE ); } } } +/** + * trw_layer_track_statistics: + * + * Show track statistics. + * ATM jump to the stats page in the properties + * TODO: consider separating the stats into an individual dialog? + */ +static void trw_layer_track_statistics ( gpointer pass_along[7] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) + trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + else + trk = g_hash_table_lookup ( vtl->routes, pass_along[3] ); + + if ( trk && trk->name ) { + vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl, + trk, + pass_along[1], // vlp + pass_along[5], // vvp + pass_along[6], // iter + TRUE ); + } +} + /* * Update the treeview of the track id - primarily to update the icon */ @@ -4855,6 +4858,18 @@ static void trw_layer_convert_track_route ( gpointer pass_along[6] ) vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); } +static void trw_layer_anonymize_times ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( track ) + vik_track_anonymize_times ( track ); +} static void trw_layer_extend_track_end ( gpointer pass_along[6] ) { @@ -4896,10 +4911,43 @@ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] ) } -static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) +/** + * + */ +static gboolean trw_layer_dem_test ( VikTrwLayer *vtl, VikLayersPanel *vlp ) +{ + // If have a vlp then perform a basic test to see if any DEM info available... + if ( vlp ) { + GList *dems = vik_layers_panel_get_all_layers_of_type (vlp, VIK_LAYER_DEM, TRUE); // Includes hidden DEM layer types + + if ( !g_list_length(dems) ) { + a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No DEM layers available, thus no DEM values can be applied.") ); + return FALSE; + } + } + return TRUE; +} + +/** + * apply_dem_data_common: + * + * A common function for applying the DEM values and reporting the results. + */ +static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTrack *track, gboolean skip_existing_elevations ) +{ + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gulong changed = vik_track_apply_dem_data ( track, skip_existing_elevations ); + // Inform user how much was changed + gchar str[64]; + const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed); + g_snprintf(str, 64, tmp_str, changed); + a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); +} + +static void trw_layer_apply_dem_data_all ( gpointer pass_along[6] ) { - /* TODO: check & warn if no DEM data, or no applicable DEM data. */ - /* Also warn if overwrite old elevation data */ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; VikTrack *track; if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) @@ -4908,7 +4956,137 @@ static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); if ( track ) - vik_track_apply_dem_data ( track ); + apply_dem_data_common ( vtl, pass_along[1], track, FALSE ); +} + +static void trw_layer_apply_dem_data_only_missing ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( track ) + apply_dem_data_common ( vtl, pass_along[1], track, TRUE ); +} + +/** + * smooth_it: + * + * A common function for applying the elevation smoothing and reporting the results. + */ +static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat ) +{ + gulong changed = vik_track_smooth_missing_elevation_data ( track, flat ); + // Inform user how much was changed + gchar str[64]; + const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed); + g_snprintf(str, 64, tmp_str, changed); + a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); +} + +/** + * + */ +static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + smooth_it ( vtl, track, FALSE ); +} + +static void trw_layer_missing_elevation_data_flat ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + smooth_it ( vtl, track, TRUE ); +} + +/** + * Commonal helper function + */ +static void wp_changed_message ( VikTrwLayer *vtl, gint changed ) +{ + gchar str[64]; + const gchar *tmp_str = ngettext("%ld waypoint changed", "%ld waypoints changed", changed); + g_snprintf(str, 64, tmp_str, changed); + a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); +} + +static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1]; + + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gint changed = 0; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + // Single Waypoint + VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); + if ( wp ) + changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE ); + } + else { + // All waypoints + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init ( &iter, vtl->waypoints ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + VikWaypoint *wp = VIK_WAYPOINT(value); + changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, FALSE ); + } + } + wp_changed_message ( vtl, changed ); +} + +static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1]; + + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gint changed = 0; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + // Single Waypoint + VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); + if ( wp ) + changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE ); + } + else { + // All waypoints + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init ( &iter, vtl->waypoints ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + VikWaypoint *wp = VIK_WAYPOINT(value); + changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, TRUE ); + } + } + wp_changed_message ( vtl, changed ); } static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) @@ -5008,6 +5186,91 @@ static void trw_layer_auto_track_view ( gpointer pass_along[6] ) } } +/* + * Refine the selected track/route with a routing engine. + * The routing engine is selected by the user, when requestiong the job. + */ +static void trw_layer_route_refine ( gpointer pass_along[6] ) +{ + static gint last_engine = 0; + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrack *trk; + + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( trk && trk->trackpoints ) + { + /* Check size of the route */ + int nb = vik_track_get_tp_count(trk); + if (nb > 100) { + GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER (vtl), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, + _("Refining a track with many points (%d) is unlikely to yield sensible results. Do you want to Continue?"), + nb); + gint response = gtk_dialog_run ( GTK_DIALOG(dialog) ); + gtk_widget_destroy ( dialog ); + if (response != GTK_RESPONSE_OK ) + return; + } + /* Select engine from dialog */ + GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Refine Route with Routing Engine..."), + VIK_GTK_WINDOW_FROM_LAYER (vtl), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + NULL); + GtkWidget *label = gtk_label_new ( _("Select routing engine") ); + gtk_widget_show_all(label); + + gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 0 ); + + GtkWidget * combo = vik_routing_ui_selector_new ( (Predicate)vik_routing_engine_supports_refine, NULL ); + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), last_engine); + gtk_widget_show_all(combo); + + gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), combo, TRUE, TRUE, 0 ); + + gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT ); + + if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + /* Dialog validated: retrieve selected engine and do the job */ + last_engine = gtk_combo_box_get_active ( GTK_COMBO_BOX(combo) ); + VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine); + + /* Change cursor */ + vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) ); + + /* Force saving track */ + /* FIXME: remove or rename this hack */ + vtl->route_finder_check_added_track = TRUE; + + /* the job */ + vik_routing_engine_refine (routing, vtl, trk); + + /* FIXME: remove or rename this hack */ + if ( vtl->route_finder_added_track ) + vik_track_calculate_bounds ( vtl->route_finder_added_track ); + + vtl->route_finder_added_track = NULL; + vtl->route_finder_check_added_track = FALSE; + + vik_layer_emit_update ( VIK_LAYER(vtl) ); + + /* Restore cursor */ + vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) ); + } + gtk_widget_destroy ( dialog ); + } +} + static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); @@ -7190,6 +7453,11 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_statistics), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + GtkWidget *goto_submenu; goto_submenu = gtk_menu_new (); item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") ); @@ -7331,6 +7599,70 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); gtk_widget_show ( item ); + GtkWidget *transform_submenu; + transform_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu ); + + GtkWidget *dem_submenu; + dem_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_all), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values")); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_only_missing), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values")); + gtk_widget_show ( item ); + + GtkWidget *smooth_submenu; + smooth_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("_Smooth Missing Elevation Data") ); + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smooth_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolated") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_interp), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Interpolate between known elevation values to derive values for the missing elevations")); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Flat") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_flat), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Set unknown elevation values to the last known value")); + gtk_widget_show ( item ); + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_widget_show ( item ); + + // Routes don't have timestamps - so this is only available for tracks + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01")); + gtk_widget_show ( item ); + } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") ); else @@ -7340,6 +7672,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("Refine Route...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_route_refine), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */ if ( vlp ) { if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) @@ -7352,12 +7692,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); } - item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") ); else @@ -7376,15 +7710,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) - item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") ); - else - item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c @@ -7473,6 +7798,37 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men } } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + GtkWidget *transform_submenu; + transform_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu ); + + GtkWidget *dem_submenu; + dem_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_all), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values")); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_only_missing), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values")); + gtk_widget_show ( item ); + } + + gtk_widget_show_all ( GTK_WIDGET(menu) ); + return rv; } @@ -7938,8 +8294,12 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve // Determine if working on a waypoint or a trackpoint if ( t->is_waypoint ) { + // Update waypoint position vtl->current_wp->coord = new_coord; trw_layer_calculate_bounds_waypoints ( vtl ); + // Reset waypoint pointer + vtl->current_wp = NULL; + vtl->current_wp_id = NULL; } else { if ( vtl->current_tpl ) { @@ -7948,17 +8308,13 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve if ( vtl->current_tp_track ) vik_track_calculate_bounds ( vtl->current_tp_track ); - if ( vtl->tpwin ) + if ( vtl->tpwin ) if ( vtl->current_tp_track ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin } } - // Reset - vtl->current_wp = NULL; - vtl->current_wp_id = NULL; - trw_layer_cancel_current_tp ( vtl, FALSE ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -8777,7 +9133,7 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) )) { gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")); - if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name, FALSE ) ) ) + if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ) ) ) { new_track_create_common ( vtl, name ); g_free ( name ); @@ -8810,7 +9166,7 @@ static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) ) { gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")); - if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->routes, name, TRUE ) ) ) { + if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ) ) ) { new_route_create_common ( vtl, name ); g_free ( name ); } @@ -9356,7 +9712,8 @@ static void trw_layer_sort_all ( VikTrwLayer *vtl ) static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file ) { - trw_layer_verify_thumbnails ( vtl, vvp ); + if ( VIK_LAYER(vtl)->realized ) + trw_layer_verify_thumbnails ( vtl, vvp ); trw_layer_track_alloc_colors ( vtl ); trw_layer_calculate_bounds_waypoints ( vtl ); @@ -9577,12 +9934,10 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) { VikMapsLayer *vml; - gint selected_map, default_map; + gint selected_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]; @@ -9600,49 +9955,35 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) 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); + a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No map layer in use. Create one first") ); return; } + // Convert from list of vmls to list of names. Allowing the user to select one of them 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; + int i; 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); - } + *lp++ = vml; + *np++ = vik_maps_layer_get_map_label(vml); vmls = vmls->next; } + // Mark end of the array lists *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++) { + for (default_zoom = 0; default_zoom < G_N_ELEMENTS(zoom_vals); 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; + default_zoom = (default_zoom == G_N_ELEMENTS(zoom_vals)) ? G_N_ELEMENTS(zoom_vals) - 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)) + if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, 0, zoomlist, default_zoom, &selected_map, &selected_zoom)) goto done; vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);