From fe727bbe62d293878e0a75a9cf9f420c0eae03cb Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Mon, 16 Jan 2012 03:13:00 +0000 Subject: [PATCH] Add Tile Map Service downloading This uses map tiles directly from openstreetmap.org. The problem with this is that those tiles are rendered using a Mercator projections which is non-linear with respect to latitude. Two things must be done to properly correct for this: 1. Split tiles at the correct location. With the Mercator projection, the midpoint of a tile is the midpoint of the longitude but not the midpoint of the latitude. Correcting this very important because it prevent tiles from being drawn in entirely the wrong place. 2. Morph each tile to lat-lon projection when it is drawn. This could possibly be done with a OpenGL fragment shader. This noticeable when zoomed out so it's not too bad to just ignore the issue.. The web based map servers have similar issues with land area at high-up zoom levels. Eventually we'll want to fetch the XML and render the maps locally.. --- src/data/Makefile.am | 2 + src/data/grits-tms.c | 122 +++++++++++++++++++++++++++++++++++++++++++ src/data/grits-tms.h | 42 +++++++++++++++ src/grits-viewer.h | 6 +++ src/grits.h | 1 + src/plugins/map.c | 5 ++ src/plugins/map.h | 1 + src/tile-test.c | 30 +++++++++++ 8 files changed, 209 insertions(+) create mode 100644 src/data/grits-tms.c create mode 100644 src/data/grits-tms.h diff --git a/src/data/Makefile.am b/src/data/Makefile.am index 5a8c806..c193fc0 100644 --- a/src/data/Makefile.am +++ b/src/data/Makefile.am @@ -9,12 +9,14 @@ grits_data_includedir = $(includedir)/grits/data grits_data_include_HEADERS = \ grits-data.h \ grits-http.h \ + grits-tms.h \ grits-wms.h noinst_LTLIBRARIES = libgrits-data.la libgrits_data_la_SOURCES = \ grits-data.c grits-data.h \ grits-http.c grits-http.h \ + grits-tms.c grits-tms.h \ grits-wms.c grits-wms.h libgrits_data_la_LDFLAGS = -static diff --git a/src/data/grits-tms.c b/src/data/grits-tms.c new file mode 100644 index 0000000..cfe84f5 --- /dev/null +++ b/src/data/grits-tms.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2009, 2012 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include + +#include "grits-tms.h" + +static gchar *_make_uri(GritsTms *tms, GritsTile *tile) +{ + +#if 0 + /* This doesn't make any sense.. */ + gdouble lon_rad = deg2rad(tile->edge.n + tile->edge.s)/2; + gdouble lat_rad = deg2rad(tile->edge.e + tile->edge.w)/2; + g_message("%lf,%lf", lat_rad, lon_rad); + + /* Reproject the coordinates to the Mercator projection: */ + gdouble x = lon_rad; + gdouble y = log(tan(lat_rad) + 1.0/cos(lat_rad)); + + /* Transform range of x and y to 0 - 1 and shift origin to top left */ + x = (1.0 + (x / G_PI)) / 2.0; + y = (1.0 - (y / G_PI)) / 2.0; + + /* Calculate the number of tiles across the map, n, using 2^zoom */ + gint zoom = 0; + for (GritsTile *tmp = tile->parent; tmp; tmp = tmp->parent) + zoom++; + gint n = pow(2, zoom); + + /* Multiply x and y by n. Round results down to give tilex and tiley. */ + gint xtile = x * n; + gint ytile = y * n; + + g_message("xy=%f,%f zoom=%d n=%d xy_tiles=%d,%d", + x, y, zoom, n, xtile, ytile); +#endif + +#if 1 + /* This is broken */ + gint zoom = 0; + for (GritsTile *tmp = tile->parent; tmp; tmp = tmp->parent) + zoom++; + gint breath = pow(2,zoom); + + gdouble lon_pos = (tile->edge.e+tile->edge.w)/2 + 180; + gdouble lat_pos = -(tile->edge.n+tile->edge.s)/2 + 90 - 4.9489; + + gdouble lon_total = 360; + gdouble lat_total = 85.0511*2; + + gdouble lon_pct = lon_pos / lon_total; + gdouble lat_pct = lat_pos / lat_total; + + gint xtile = lon_pct * breath; + gint ytile = lat_pct * breath; + + //g_message("bbok=%f,%f,%f,%f", + // tile->edge.n, tile->edge.s, + // tile->edge.e, tile->edge.w); + //g_message("pos=%f,%f total=%f,%f pct=%f,%f tile=%d,%d", + // lon_pos, lat_pos, + // lon_total, lat_total, + // lon_pct, lat_pct, + // xtile, ytile); +#endif + + // http://tile.openstreetmap.org///.png + return g_strdup_printf("%s/%d/%d/%d.%s", + tms->uri_prefix, zoom, xtile, ytile, tms->extension); +} + +gchar *grits_tms_fetch(GritsTms *tms, GritsTile *tile, GritsCacheType mode, + GritsChunkCallback callback, gpointer user_data) +{ + /* Get file path */ + gchar *uri = _make_uri(tms, tile); + gchar *tilep = grits_tile_get_path(tile); + gchar *local = g_strdup_printf("%s%s", tilep, tms->extension); + gchar *path = grits_http_fetch(tms->http, uri, local, + mode, callback, user_data); + g_free(uri); + g_free(tilep); + g_free(local); + return path; +} + +GritsTms *grits_tms_new(const gchar *uri_prefix, + const gchar *prefix, const gchar *extension) +{ + GritsTms *tms = g_new0(GritsTms, 1); + tms->http = grits_http_new(prefix); + tms->uri_prefix = g_strdup(uri_prefix); + tms->extension = g_strdup(extension); + return tms; +} + +void grits_tms_free(GritsTms *tms) +{ + grits_http_free(tms->http); + g_free(tms->uri_prefix); + g_free(tms->extension); + g_free(tms); +} diff --git a/src/data/grits-tms.h b/src/data/grits-tms.h new file mode 100644 index 0000000..49fb0c4 --- /dev/null +++ b/src/data/grits-tms.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GRITS_TMS_H__ +#define __GRITS_TMS_H__ + +#include + +#include "data/grits-http.h" +#include "objects/grits-tile.h" + +typedef struct _GritsTms GritsTms; + +struct _GritsTms { + GritsHttp *http; + gchar *uri_prefix; + gchar *cache_prefix; + gchar *extension; +}; + +gchar *grits_tms_fetch(GritsTms *tms, GritsTile *tile, GritsCacheType mode, + GritsChunkCallback callback, gpointer user_data); + +GritsTms *grits_tms_new(const gchar *uri_prefix, const gchar *cache_prefix, const gchar *extention); + +void grits_tms_free(GritsTms *self); + +#endif diff --git a/src/grits-viewer.h b/src/grits-viewer.h index 0fe7365..b7ff216 100644 --- a/src/grits-viewer.h +++ b/src/grits-viewer.h @@ -38,6 +38,12 @@ #include #include +/* Projections */ +enum { + GRITS_PROJ_MERCATOR, + GRITS_PROJ_EQUIRECTANGULAR, +} GritsProjection; + /* Rendering levels */ /** * GRITS_LEVEL_BACKGROUND: diff --git a/src/grits.h b/src/grits.h index 540120c..fa8f001 100644 --- a/src/grits.h +++ b/src/grits.h @@ -27,6 +27,7 @@ /* Grits data */ #include #include +#include #include /* Grits objects */ diff --git a/src/plugins/map.c b/src/plugins/map.c index 96f2c99..aa4d0f2 100644 --- a/src/plugins/map.c +++ b/src/plugins/map.c @@ -86,6 +86,7 @@ static void _load_tile(GritsTile *tile, gpointer _map) } /* Download tile */ + //gchar *path = grits_tms_fetch(map->tms, tile, GRITS_ONCE, NULL, NULL); gchar *path = grits_wms_fetch(map->wms, tile, GRITS_ONCE, NULL, NULL); if (!path) return; // Canceled/error @@ -217,6 +218,9 @@ static void grits_plugin_map_init(GritsPluginMap *map) g_debug("GritsPluginMap: init"); /* Set defaults */ map->threads = g_thread_pool_new(_update_tiles, map, 1, FALSE, NULL); + //map->tiles = grits_tile_new(NULL, 85.0511, -85.0511, EAST, WEST); + //map->wms = grits_tms_new("http://tile.openstreetmap.org", + // "osm/", "png"); map->tiles = grits_tile_new(NULL, NORTH, SOUTH, EAST, WEST); map->wms = grits_wms_new( "http://vmap0.tiles.osgeo.org/wms/vmap0", @@ -247,6 +251,7 @@ static void grits_plugin_map_finalize(GObject *gobject) g_debug("GritsPluginMap: finalize"); GritsPluginMap *map = GRITS_PLUGIN_MAP(gobject); /* Free data */ + //grits_wms_free(map->tms); grits_wms_free(map->wms); grits_tile_free(map->tiles, _free_tile, map); G_OBJECT_CLASS(grits_plugin_map_parent_class)->finalize(gobject); diff --git a/src/plugins/map.h b/src/plugins/map.h index 91e96ab..5161837 100644 --- a/src/plugins/map.h +++ b/src/plugins/map.h @@ -36,6 +36,7 @@ struct _GritsPluginMap { /* instance members */ GritsViewer *viewer; GritsTile *tiles; + GritsTms *tms; GritsWms *wms; GThreadPool *threads; gulong sigid; diff --git a/src/tile-test.c b/src/tile-test.c index 9a4fd81..8be6fe9 100644 --- a/src/tile-test.c +++ b/src/tile-test.c @@ -20,6 +20,7 @@ #include "grits-util.h" #include "data/grits-wms.h" +#include "data/grits-tms.h" #include "objects/grits-tile.h" struct CacheState { @@ -98,6 +99,32 @@ gpointer do_osm_cache(gpointer _image) return NULL; } +gpointer do_osm2_cache(gpointer _image) +{ + GtkImage *image = _image; + g_message("Creating osm2 tile"); + GritsTile *tile = grits_tile_new(NULL, 85.0511, -85.0511, EAST, WEST); + tile->children[0][1] = grits_tile_new(tile, 85.0511, 0, 0, WEST); + tile = tile->children[0][1]; + + g_message("Fetching osm2 image"); + GritsTms *osm2_tms = grits_tms_new("http://tile.openstreetmap.org", + "tms_test/", "png"); + const char *path = grits_tms_fetch(osm2_tms, tile, GRITS_ONCE, NULL, NULL); + + g_message("Loading osm2 image: [%s]", path); + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, NULL); + gdk_threads_enter(); + gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf); + gdk_threads_leave(); + + g_message("Cleaning osm2 up"); + grits_tms_free(osm2_tms); + grits_tile_free(tile, NULL, NULL); + return NULL; +} + + gboolean key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { if (event->keyval == GDK_q) @@ -119,12 +146,14 @@ int main(int argc, char **argv) GtkWidget *bmng_image = gtk_image_new(); GtkWidget *srtm_image = gtk_image_new(); GtkWidget *osm_image = gtk_image_new(); + GtkWidget *osm2_image = gtk_image_new(); gtk_container_add(GTK_CONTAINER(win), vbox1); gtk_box_pack_start(GTK_BOX(vbox1), scroll, TRUE, TRUE, 0); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox2); gtk_box_pack_start(GTK_BOX(vbox2), bmng_image, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox2), srtm_image, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox2), osm_image, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox2), osm2_image, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox1), status, FALSE, FALSE, 0); g_signal_connect(win, "key-press-event", G_CALLBACK(key_press_cb), NULL); g_signal_connect(win, "destroy", gtk_main_quit, NULL); @@ -133,6 +162,7 @@ int main(int argc, char **argv) g_thread_create(do_bmng_cache, bmng_image, FALSE, NULL); g_thread_create(do_osm_cache, osm_image, FALSE, NULL); + g_thread_create(do_osm2_cache, osm2_image, FALSE, NULL); gtk_widget_show_all(win); gtk_main(); -- 2.43.2