From: Andy Spencer Date: Mon, 9 Nov 2009 12:02:23 +0000 (+0000) Subject: Add GisTile and GisWms and update wms_test accordingly X-Git-Tag: v0.3~4 X-Git-Url: http://pileus.org/git/?p=grits;a=commitdiff_plain;h=2e575e2c348f44d3c723ac344b7296492c76f77a Add GisTile and GisWms and update wms_test accordingly GisTile: * Represents a lat-lon tile * May contain pointers to child tiles of higher resolution GisWms: * Contains Web Map Service support functions GisWms and GisTile roughly translate to WmsInfo and WmsCacheNode. The main difference being that the new versions are more independent of each other so non-wms downloaders can be used in the future. The other major difference is that GisTile is not transparent as WmsCacheNode was. That is, there is no gis_tile_fetch function which automatically updates the tiles. --- diff --git a/src/Makefile.am b/src/Makefile.am index 5c3c3a8..5e3da6d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,8 @@ gis_include_HEADERS = \ gis-opengl.h \ gis-plugin.h \ gis-data.h \ + gis-tile.h \ + gis-wms.h \ gpqueue.h \ roam.h libgis_la_SOURCES = \ @@ -26,6 +28,8 @@ libgis_la_SOURCES = \ gis-plugin.c gis-plugin.h \ gis-marshal.c gis-marshal.h \ gis-data.c gis-data.h \ + gis-tile.c gis-tile.h \ + gis-wms.c gis-wms.h \ roam.c roam.h \ gpqueue.c gpqueue.h libgis_la_CPPFLAGS = $(AM_CPPFLAGS) \ @@ -36,14 +40,14 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libgis.pc # Test programs -bin_PROGRAMS = gis_test # wms_test +bin_PROGRAMS = gis_test wms_test gis_test_SOURCES = gis_test.c gis.h gis_test_LDFLAGS = -static gis_test_LDADD = $(AM_LDADD) libgis.la -# wms_test_SOURCES = wms_test.c gis-world.c gis-world.h -# wms_test_LDADD = $(AM_LDADD) +wms_test_SOURCES = wms_test.c gis-world.c gis-world.h gis-wms.c gis-wms.h gis-tile.c gis-tile.h +wms_test_LDADD = $(AM_LDADD) MAINTAINERCLEANFILES = Makefile.in diff --git a/src/gis-tile.c b/src/gis-tile.c new file mode 100644 index 0000000..ab45616 --- /dev/null +++ b/src/gis-tile.c @@ -0,0 +1,68 @@ +/* + * 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 . + */ + +#include +#include + +#include "gis-world.h" +#include "gis-tile.h" + +gchar *gis_tile_path_table[2][2] = { + {".00", ".01"}, + {".10", ".11"}, +}; + +GisTile *gis_tile_new(GisTile *parent, + gdouble n, gdouble s, gdouble e, gdouble w) +{ + GisTile *self = g_new0(GisTile, 1); + self->parent = parent; + self->edge.n = n; + self->edge.s = s; + self->edge.e = e; + self->edge.w = w; + return self; +} + +gchar *gis_tile_get_path(GisTile *child) +{ + /* This could be easily cached if necessasairy */ + int x, y; + GList *parts = NULL; + for (GisTile *parent = child->parent; parent; child = parent, parent = child->parent) + gis_tile_foreach_index(child, x, y) + if (parent->children[x][y] == child) + parts = g_list_prepend(parts, gis_tile_path_table[x][y]); + GString *path = g_string_new(""); + for (; parts; parts = parts->next) + g_string_append(path, parts->data); + g_list_free(parts); + return g_string_free(path, FALSE); +} + + +void gis_tile_free(GisTile *self, GisTileFreeFunc free_func, gpointer user_data) +{ + if (!self) + return; + GisTile *child; + gis_tile_foreach(self, child) + gis_tile_free(child, free_func, user_data); + if (free_func) + free_func(self, user_data); + g_free(self); +} diff --git a/src/gis-tile.h b/src/gis-tile.h new file mode 100644 index 0000000..12d397d --- /dev/null +++ b/src/gis-tile.h @@ -0,0 +1,66 @@ +/* + * 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 __GIS_TILE_H__ +#define __GIS_TILE_H__ + +#include +#include + +typedef struct _GisTile GisTile; + +#define gis_tile_foreach(tile, child) \ + for (int _x = 0; _x < G_N_ELEMENTS(tile->children); _x++) \ + for (int _y = 0; child = tile->children[_x][_y], \ + _y < G_N_ELEMENTS(tile->children[_x]); _y++) \ + +#define gis_tile_foreach_index(tile, x, y) \ + for (x = 0; x < G_N_ELEMENTS(tile->children); x++) \ + for (y = 0; y < G_N_ELEMENTS(tile->children[x]); y++) + +typedef void (*GisTileLoadFunc)(GisTile *tile, gpointer user_data); +typedef void (*GisTileFreeFunc)(GisTile *tile, gpointer user_data); + +struct _GisTile { + /* Pointer to the tile data */ + gpointer data; + + /* North,South,East,West limits */ + struct { + gdouble n,s,e,w; + } edge; + + /* Pointers to parent/child nodes */ + GisTile *parent; + GisTile *children[2][2]; +}; + +/* Path to string table, keep in sync with tile->children */ +extern gchar *gis_tile_path_table[2][2]; + +/* Allocate a new Tile */ +GisTile *gis_tile_new(GisTile *parent, + gdouble n, gdouble s, gdouble e, gdouble w); + +/* Return a string representation of the tile's path */ +gchar *gis_tile_get_path(GisTile *child); + +/* Free a tile and all it's children */ +void gis_tile_free(GisTile *root, + GisTileFreeFunc free_func, gpointer user_data); + +#endif diff --git a/src/gis-wms.c b/src/gis-wms.c new file mode 100644 index 0000000..0c15e87 --- /dev/null +++ b/src/gis-wms.c @@ -0,0 +1,143 @@ +/* + * 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 . + */ + +/** + * http://www.nasa.network.com/elev? + * SERVICE=WMS& + * VERSION=1.1.0& + * REQUEST=GetMap& + * LAYERS=bmng200406& + * STYLES=& + * SRS=EPSG:4326& + * BBOX=-180,-90,180,90& + * FORMAT=image/jpeg& + * WIDTH=600& + * HEIGHT=300 + * + * http://www.nasa.network.com/elev? + * SERVICE=WMS& + * VERSION=1.1.0& + * REQUEST=GetMap& + * LAYERS=srtm30& + * STYLES=& + * SRS=EPSG:4326& + * BBOX=-180,-90,180,90& + * FORMAT=application/bil32& + * WIDTH=600& + * HEIGHT=300 + */ + +#include +#include +#include + +#include "gis-wms.h" + +static gchar *_make_uri(GisWms *wms, GisTile *tile) +{ + return g_strdup_printf( + "%s?" + "SERVICE=WMS&" + "VERSION=1.1.0&" + "REQUEST=GetMap&" + "LAYERS=%s&" + "STYLES=&" + "SRS=EPSG:4326&" + "FORMAT=%s&" + "WIDTH=%d&" + "HEIGHT=%d&" + "BBOX=%f,%f,%f,%f", + wms->uri_prefix, + wms->uri_layer, + wms->uri_format, + wms->width, + wms->height, + tile->edge.w, + tile->edge.s, + tile->edge.e, + tile->edge.n); +} + +void gis_wms_soup_chunk_cb(SoupMessage *message, SoupBuffer *chunk, gpointer _file) +{ + FILE *file = _file; + if (!SOUP_STATUS_IS_SUCCESSFUL(message->status_code)) + return; + goffset total = soup_message_headers_get_content_length(message->response_headers); + if (fwrite(chunk->data, chunk->length, 1, file) != 1) + g_warning("GisWms: soup_chunk_cb - eror writing data"); +} + +char *gis_wms_make_local(GisWms *self, GisTile *tile) +{ + /* Get file path */ + gchar *tile_path = gis_tile_get_path(tile); + gchar *path = g_strdup_printf("%s/wms/%s%s%s", + g_get_user_cache_dir(), + self->cache_prefix, + tile_path, + self->cache_ext); + g_free(tile_path); + + /* Return if it already exists */ + if (g_file_test(path, G_FILE_TEST_EXISTS)) + return path; + + /* Open temp file for writing */ + gchar *tmp_path = g_strconcat(path, ".part", NULL); + gchar *dirname = g_path_get_dirname(tmp_path); + g_mkdir_with_parents(dirname, 0755); + g_free(dirname); + FILE *file = fopen(tmp_path, "a"); + + /* Download file */ + gchar *uri = _make_uri(self, tile); + SoupMessage *message = soup_message_new("GET", uri); + g_signal_connect(message, "got-chunk", G_CALLBACK(gis_wms_soup_chunk_cb), file); + soup_message_headers_set_range(message->request_headers, ftell(file), -1); + int status = soup_session_send_message(self->soup, message); + g_free(uri); + + /* Clean up */ + fclose(file); + rename(tmp_path, path); + g_free(tmp_path); + return path; +} + +GisWms *gis_wms_new( + gchar *uri_prefix, gchar *uri_layer, gchar *uri_format, + gchar *cache_prefix, gchar *cache_ext, + gint width, gint height) +{ + GisWms *self = g_new0(GisWms, 1); + self->uri_prefix = uri_prefix; + self->uri_layer = uri_layer; + self->uri_format = uri_format; + self->cache_prefix = cache_prefix; + self->cache_ext = cache_ext; + self->width = width; + self->height = height; + self->soup = soup_session_sync_new(); + return self; +} + +void gis_wms_free(GisWms *self) +{ + g_object_unref(self->soup); + g_free(self); +} diff --git a/src/gis-wms.h b/src/gis-wms.h new file mode 100644 index 0000000..4151cbf --- /dev/null +++ b/src/gis-wms.h @@ -0,0 +1,49 @@ +/* + * 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 __GIS_WMS_H__ +#define __GIS_WMS_H__ + +#include +#include +#include + +#include "gis-tile.h" + +typedef struct _GisWms GisWms; + +struct _GisWms { + gchar *uri_prefix; + gchar *uri_layer; + gchar *uri_format; + gchar *cache_prefix; + gchar *cache_ext; + gint width; + gint height; + SoupSession *soup; +}; + +char *gis_wms_make_local(GisWms *wms, GisTile *tile); + +GisWms *gis_wms_new( + gchar *uri_prefix, gchar *uri_layer, gchar *uri_format, + gchar *cache_prefix, gchar *cache_ext, + gint width, gint height); + +void gis_wms_free(GisWms *self); + +#endif diff --git a/src/gis-world.h b/src/gis-world.h index 93c47e3..3a34780 100644 --- a/src/gis-world.h +++ b/src/gis-world.h @@ -26,6 +26,10 @@ #define EARTH_R (6371000) #define EARTH_C (2*M_PI*EARTH_R) +#define NORTH 90 +#define SOUTH -90 +#define EAST 180 +#define WEST -180 /** * Terms diff --git a/src/gis.h b/src/gis.h index 365c843..6ff9789 100644 --- a/src/gis.h +++ b/src/gis.h @@ -26,6 +26,8 @@ /* GIS helprs */ #include "gis-data.h" +#include "gis-tile.h" +#include "gis-wms.h" /* Plugins */ #include "gis-plugin.h" diff --git a/src/wms_test.c b/src/wms_test.c index 59868e5..c456659 100644 --- a/src/wms_test.c +++ b/src/wms_test.c @@ -1,7 +1,9 @@ #include #include -#include "wms.h" +#include "gis-world.h" +#include "gis-tile.h" +#include "gis-wms.h" struct CacheState { GtkWidget *image; @@ -9,12 +11,6 @@ struct CacheState { GtkWidget *progress; }; -void done_callback(WmsCacheNode *node, gpointer _state) -{ - struct CacheState *state = _state; - g_message("done_callback: %p->%p", node, node->data); - gtk_image_set_from_pixbuf(GTK_IMAGE(state->image), node->data); -} void chunk_callback(gsize cur, gsize total, gpointer _state) { @@ -33,6 +29,32 @@ void chunk_callback(gsize cur, gsize total, gpointer _state) gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(state->progress), (gdouble)cur/total); } +gpointer do_cache(gpointer _image) +{ + GtkImage *image = _image; + g_message("Creating tile"); + GisTile *tile = gis_tile_new(NULL, NORTH, SOUTH, EAST, WEST); + tile->children[0][1] = gis_tile_new(tile, NORTH, 0, 0, WEST); + tile = tile->children[0][1]; + + g_message("Fetching image"); + GisWms *bmng_wms = gis_wms_new( + "http://www.nasa.network.com/wms", "bmng200406", "image/jpeg", + "bmng", ".jpg", 512, 256); + const char *path = gis_wms_make_local(bmng_wms, tile); + + g_message("Loading 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 up"); + gis_wms_free(bmng_wms); + gis_tile_free(tile, NULL, NULL); + return NULL; +} + gboolean key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { if (event->keyval == GDK_q) @@ -64,22 +86,10 @@ int main(int argc, char **argv) gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - struct CacheState bmng_state = {bmng_image, status, NULL}; - struct CacheState srtm_state = {srtm_image, status, NULL}; - - gdouble res = 200, lon = -101.76, lat = 46.85; - - WmsInfo *bmng_info = wms_info_new_for_bmng(bmng_pixbuf_loader, bmng_pixbuf_freeer); - wms_info_fetch_cache(bmng_info, NULL, res, lat, lon, chunk_callback, done_callback, &bmng_state); - - WmsInfo *srtm_info = wms_info_new_for_srtm(srtm_pixbuf_loader, srtm_pixbuf_freeer); - wms_info_fetch_cache(srtm_info, NULL, res, lat, lon, chunk_callback, done_callback, &srtm_state); + g_thread_create(do_cache, bmng_image, FALSE, NULL); gtk_widget_show_all(win); gtk_main(); - wms_info_free(bmng_info); - wms_info_free(srtm_info); - return 0; }