From 4c05c0df314a58b378281e1cb612bad3f7082cb7 Mon Sep 17 00:00:00 2001 From: Kaj-Michael Lang Date: Wed, 20 Aug 2008 14:52:02 +0300 Subject: [PATCH] MapWidget: Start to move and re-implement tile downloading --- libs/libgtkmap/Makefile.am | 4 +- libs/libgtkmap/tilerepo.c | 168 ++++++++++++++++++++++++++++++++++++- libs/libgtkmap/tilerepo.h | 18 ++++ 3 files changed, 186 insertions(+), 4 deletions(-) diff --git a/libs/libgtkmap/Makefile.am b/libs/libgtkmap/Makefile.am index 31988f1..42e8c74 100644 --- a/libs/libgtkmap/Makefile.am +++ b/libs/libgtkmap/Makefile.am @@ -30,8 +30,8 @@ libgtkmap_la_SOURCES = gtkmap.c gtkmap.h \ path.c path.h position.c position.h \ tilerepo.c tilerepo.h \ $(TOPDIR)/latlon.c $(TOPDIR)/image-cache.c -libgtkmap_la_CFLAGS = $(GLIBGTK_CFLAGS) $(GNOME_VFS_CFLAGS) $(LIBXML2_CFLAGS) $(GTKGLEXT_CFLAGS) $(defines) -libgtkmap_la_LIBADD = $(GLIBGTK_LIBS) $(GNOME_VFS_LIBS) $(LIBXML2_LIBS) $(GTKGLEXT_LIBS) +libgtkmap_la_CFLAGS = $(GLIBGTK_CFLAGS) $(GNOME_VFS_CFLAGS) $(LIBXML2_CFLAGS) $(GTKGLEXT_CFLAGS) $(LIBCURL_CFLAGS) $(defines) +libgtkmap_la_LIBADD = $(GLIBGTK_LIBS) $(GNOME_VFS_LIBS) $(LIBXML2_LIBS) $(GTKGLEXT_LIBS) $(LIBCURL_LIBS) libgtkmap_la_LDFLAGS = -lm -no-undefined map_widget_test_SOURCES = map-widget-test.c diff --git a/libs/libgtkmap/tilerepo.c b/libs/libgtkmap/tilerepo.c index 236b0ee..0a2ed9a 100644 --- a/libs/libgtkmap/tilerepo.c +++ b/libs/libgtkmap/tilerepo.c @@ -42,6 +42,17 @@ enum { PROP_CACHE_DIR, }; +typedef struct _ProgressUpdateInfo ProgressUpdateInfo; +struct _ProgressUpdateInfo { + gchar *src_str; + gchar *dest_str; + TileRepo *repo; + guint tilex, tiley, zoom; /* for refresh. */ + gint retries; /* if equal to zero, it means we're DELETING maps. */ + guint priority; + FILE *file; +}; + #if 0 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TILE_REPO_TYPE, TileRepoPrivate)) #endif @@ -65,8 +76,21 @@ TileRepo *tr=TILE_REPO(object); switch (prop_id) { case PROP_NAME: + if (tr->name) + g_free(tr->name); + tr->name=g_value_dup_string(value); + break; case PROP_URL: + if (tr->url) + g_free(tr->url); + tr->url=g_value_dup_string(value); + tile_repo_set_type(tr); + break; case PROP_CACHE_DIR: + if (tr->cache_dir) + g_free(tr->cache_dir); + tr->cache_dir=g_value_dup_string(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -80,8 +104,14 @@ TileRepo *tr=TILE_REPO(object); switch (prop_id) { case PROP_NAME: + g_value_set_string(value, tr->name); + break; case PROP_URL: + g_value_set_string(value, tr->url); + break; case PROP_CACHE_DIR: + g_value_set_string(value, tr->cache_dir); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -99,6 +129,48 @@ object_class->set_property=tile_repo_set_property; object_class->get_property=tile_repo_get_property; } +static gboolean +get_next_pui(gpointer key, gpointer value, ProgressUpdateInfo **data) +{ +*data = key; +return TRUE; +} + +static gint +download_comparefunc(const ProgressUpdateInfo *a, const ProgressUpdateInfo *b, gpointer user_data) +{ +gint diff = (a->priority - b->priority); +if (diff) + return diff; +diff = (a->tilex - b->tilex); +if (diff) + return diff; +diff = (a->tiley - b->tiley); +if (diff) + return diff; +diff = (a->zoom - b->zoom); +if (diff) + return diff; +diff = (a->repo - b->repo); +if (diff) + return diff; +/* Otherwise, deletes are "greatest" (least priority). */ +if (!a->retries) + return (b->retries ? -1 : 0); +else if (!b->retries) + return (a->retries ? 1 : 0); +/* Do updates after non-updates (because they'll both be done anyway). */ +return (a->retries - b->retries); +} + +static void +progress_update_info_free(ProgressUpdateInfo *pui) +{ +g_free(pui->src_str); +g_free(pui->dest_str); +g_slice_free(ProgressUpdateInfo, pui); +} + /** * tile_repo_new: * @@ -125,6 +197,17 @@ tr->cache_dir=NULL; tr->dl_zoom_steps=1; tr->double_size=0; tr->nextable=FALSE; + +tr->download.cond=g_cond_new(); +tr->download.mutex=g_mutex_new(); +tr->download.curl_easy_queue=g_queue_new(); +tr->download.pui_tree=g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL); +tr->download.downloading_tree=g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL); +tr->download.pui_by_easy=g_hash_table_new(g_direct_hash, g_direct_equal); +tr->download.curl_multi=curl_multi_init(); +#ifdef CURL_PIPELINE +curl_multi_setopt(tr->download.curl_multi, CURLMOPT_PIPELINING, 1); +#endif } /** @@ -149,8 +232,6 @@ TileRepo *tr; tr=tile_repo_new(); g_return_val_if_fail(tr, NULL); -g_debug("REPOSTR: %s", str); - /* Parse name. */ token=strsep(&str, "\n\t"); if (token) @@ -205,6 +286,11 @@ return g_strdup_printf("%s\t%s\t%s\t%d\t%d\t%d\t%d", tr->double_size, tr->nextable); } +static void +download_stop(TileRepo *tr) +{ +} + /** * tile_repo_free: * @tr @@ -224,6 +310,30 @@ if (tr->cache_dir) if (tr->icache) image_cache_free(tr->icache); +if (tr->download.curl_multi) { + gint num_transfers; + + /* Finish up all downloads. */ + while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(tr->download.curl_multi, &num_transfers) || num_transfers) + g_debug("NT: %d", num_transfers); + + /* Stop all transfers and cleanup */ + download_stop(tr); + + curl_multi_cleanup(tr->download.curl_multi); +} + +if (tr->download.curl_sid) + g_source_remove(tr->download.curl_sid); +if (tr->download.pui_tree) + g_tree_destroy(tr->download.pui_tree); +if (tr->download.downloading_tree) + g_tree_destroy(tr->download.downloading_tree); +if (tr->download.pui_by_easy) + g_hash_table_destroy(tr->download.pui_by_easy); +if (tr->download.curl_easy_queue) + g_queue_free(tr->download.curl_easy_queue); + g_object_unref(tr); } @@ -260,6 +370,60 @@ if (g_mkdir_with_parents(tr->cache_dir, 0755)) return g_file_test(tr->cache_dir, G_FILE_TEST_EXISTS); } +static void +convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel, gchar *buffer, const gchar initial, const gchar * const quadrant) +{ +gchar *ptr = buffer; +gint n; + +if (initial) + *ptr++ = initial; + +for (n = 16 - zoomlevel; n >= 0; n--) { + gint xbit = (x >> n) & 1; + gint ybit = (y >> n) & 1; + *ptr++ = quadrant[xbit + 2 * ybit]; +} +*ptr++ = '\0'; +} + + +/** + * til + * Construct the URL that we should fetch, based on the current URI format. + * This method works differently depending on if a "%s" string is present in + * the URI format, since that would indicate a quadtree-based map coordinate + * system. + */ +static gchar * +tile_repo_construct_url(TileRepo *tr, guint tilex, guint tiley, guint zoom) +{ +switch (tr->type) { +case REPOTYPE_XYZ: + return g_strdup_printf(tr->url, tilex, tiley, zoom); +case REPOTYPE_XYZ_INV: + return g_strdup_printf(tr->url, 17 - zoom, tilex, tiley); +case REPOTYPE_QUAD_QRST: { + gchar location[32]; + convert_coords_to_quadtree_string(tilex, tiley, zoom, location, 't', "qrts"); + return g_strdup_printf(tr->url, location); + } +case REPOTYPE_QUAD_ZERO: { + /* This is a zero-based quadtree URI. */ + gchar location[32]; + convert_coords_to_quadtree_string(tilex, tiley, zoom, location, '\0', "0123"); + return g_strdup_printf(tr->url, location); + } +#ifdef MAP_DOWNLOAD_WMD +case REPOTYPE_WMS: + return map_convert_wms_to_wms(tilex, tiley, zoom, tr->url); +#endif +default: + return NULL; +} +return ""; +} + GdkPixbuf * tile_repo_load(TileRepo *tr, guint tilex, guint tiley, gint zoom, gint zoff, gboolean fast_fail) { diff --git a/libs/libgtkmap/tilerepo.h b/libs/libgtkmap/tilerepo.h index ec4e5c4..aa3fc29 100644 --- a/libs/libgtkmap/tilerepo.h +++ b/libs/libgtkmap/tilerepo.h @@ -24,6 +24,7 @@ #include #include +#include #include "image-cache.h" @@ -46,6 +47,22 @@ typedef enum { REPOTYPE_WMS /* "service=wms" */ } RepoType; +typedef struct _TileDownload TileDownload; +struct _TileDownload { + CURLM *curl_multi; + + guint num_downloads; + guint curr_download; + guint curl_sid; + + GCond* cond; + GMutex* mutex; + GQueue *curl_easy_queue; + GTree *pui_tree; + GTree *downloading_tree; + GHashTable *pui_by_easy; +}; + typedef struct _TileRepo TileRepo; struct _TileRepo { GObject parent; @@ -61,6 +78,7 @@ struct _TileRepo { gboolean nextable; ImageCache *icache; RepoType type; + TileDownload download; GtkWidget *menu_item; }; -- 2.39.5