+/* ----------- 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);
+
+}
+
+/**** lowest waypoint number calculation ***/
+static gint highest_wp_number_name_to_number(const gchar *name) {
+ if ( strlen(name) == 3 ) {
+ int n = atoi(name);
+ if ( n < 100 && name[0] != '0' )
+ return -1;
+ if ( n < 10 && name[0] != '0' )
+ return -1;
+ return n;
+ }
+ return -1;
+}
+
+
+static void highest_wp_number_reset(VikTrwLayer *vtl)
+{
+ vtl->highest_wp_number = -1;
+}
+
+static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name)
+{
+ /* if is bigger that top, add it */
+ gint new_wp_num = highest_wp_number_name_to_number(new_wp_name);
+ if ( new_wp_num > vtl->highest_wp_number )
+ vtl->highest_wp_number = new_wp_num;
+}
+
+static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name)
+{
+ /* if wasn't top, do nothing. if was top, count backwards until we find one used */
+ gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
+ if ( vtl->highest_wp_number == old_wp_num ) {
+ gchar buf[4];
+ vtl->highest_wp_number --;
+
+ g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
+ /* search down until we find something that *does* exist */
+
+ while ( vtl->highest_wp_number > 0 && ! g_hash_table_lookup ( vtl->waypoints, buf ) ) {
+ vtl->highest_wp_number --;
+ g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
+ }
+ }
+}
+
+/* get lowest unused number */
+static gchar *highest_wp_number_get(VikTrwLayer *vtl)
+{
+ gchar buf[4];
+ if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 )
+ return NULL;
+ g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 );
+ return g_strdup(buf);
+}