]> Pileus Git - grits/blob - src/plugins/map.c
255f67cf2980d1bfe31e7ec250d7e095c616d218
[grits] / src / plugins / map.c
1 /*
2  * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /**
19  * SECTION:map
20  * @short_description: Map plugin
21  *
22  * #GritsPluginMap provides map overlays. Much of this data is obtained from the
23  * OpenStreetMap project.
24  */
25
26 #include <time.h>
27 #include <glib/gstdio.h>
28
29 #include <grits.h>
30
31 #include "map.h"
32
33 #define MAX_RESOLUTION 1
34 #define TILE_WIDTH     256
35 #define TILE_HEIGHT    256
36
37 //#define MAX_RESOLUTION 100
38 //#define TILE_WIDTH     1024
39 //#define TILE_HEIGHT    512
40
41 static const guchar colormap[][2][4] = {
42         {{0x73, 0x91, 0xad}, {0x73, 0x91, 0xad, 0x00}}, // Oceans
43         {{0xf6, 0xee, 0xee}, {0xf6, 0xee, 0xee, 0x00}}, // Ground
44         {{0xff, 0xff, 0xff}, {0xff, 0xff, 0xff, 0xff}}, // Borders
45         {{0x73, 0x93, 0xad}, {0x73, 0x93, 0xad, 0x40}}, // Lakes
46         {{0xff, 0xe1, 0x80}, {0xff, 0xe1, 0x80, 0x60}}, // Cities
47 };
48
49 static void _load_tile_thread(gpointer _tile, gpointer _map)
50 {
51         GritsTile      *tile = _tile;
52         GritsPluginMap *map  = _map;
53
54         g_debug("GritsPluginMap: _load_tile_thread start %p - tile=%p",
55                         g_thread_self(), tile);
56         if (map->aborted) {
57                 g_debug("GritsPluginMap: _load_tile_thread - aborted");
58                 return;
59         }
60
61         /* Download tile */
62         gchar *path = grits_tms_fetch(map->tms, tile, GRITS_ONCE, NULL, NULL);
63         //gchar *path = grits_wms_fetch(map->wms, tile, GRITS_ONCE, NULL, NULL);
64         if (!path) return; // Canceled/error
65
66         /* Load pixbuf */
67         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, NULL);
68         if (!pixbuf) {
69                 g_warning("GritsPluginMap: _load_tile_thread - Error loading pixbuf %s", path);
70                 g_remove(path);
71                 g_free(path);
72                 return;
73         }
74         g_free(path);
75
76 #ifdef MAP_MAP_COLORS
77         /* Map texture colors, if needed */
78         gint    width  = gdk_pixbuf_get_width(pixbuf);
79         gint    height = gdk_pixbuf_get_height(pixbuf);
80         guchar *pixels = gdk_pixbuf_get_pixels(pixbuf);
81         for (int i = 0; i < width * height; i++) {
82                 for (int j = 0; j < G_N_ELEMENTS(colormap); j++) {
83                         if (pixels[i*4+0] == colormap[j][0][0] &&
84                             pixels[i*4+1] == colormap[j][0][1] &&
85                             pixels[i*4+2] == colormap[j][0][2]) {
86                                 pixels[i*4+0] = colormap[j][1][0];
87                                 pixels[i*4+1] = colormap[j][1][1];
88                                 pixels[i*4+2] = colormap[j][1][2];
89                                 pixels[i*4+3] = colormap[j][1][3];
90                                 break;
91                         }
92                 }
93         }
94 #endif
95
96         /* Load the GL texture from the main thread */
97         grits_tile_load_pixbuf(tile, pixbuf);
98         g_debug("GritsPluginMap: _load_tile_thread end %p", g_thread_self());
99 }
100
101 static void _load_tile_func(GritsTile *tile, gpointer _map)
102 {
103         g_debug("GritsPluginMap: _load_tile_func - tile=%p", tile);
104         GritsPluginMap *map = _map;
105         g_thread_pool_push(map->threads, tile, NULL);
106 }
107
108 /*************
109  * Callbacks *
110  *************/
111 static void _on_location_changed(GritsViewer *viewer,
112                 gdouble lat, gdouble lon, gdouble elev, GritsPluginMap *map)
113 {
114         GritsPoint eye = {lat, lon, elev};
115         grits_tile_update(map->tiles, &eye,
116                         MAX_RESOLUTION, TILE_WIDTH, TILE_WIDTH,
117                         _load_tile_func, map);
118         grits_tile_gc(map->tiles, time(NULL)-10, NULL, map);
119 }
120
121 /***********
122  * Methods *
123  ***********/
124 /**
125  * grits_plugin_map_new:
126  * @viewer: the #GritsViewer to use for drawing
127  *
128  * Create a new instance of the map plugin.
129  *
130  * Returns: the new #GritsPluginMap
131  */
132 GritsPluginMap *grits_plugin_map_new(GritsViewer *viewer)
133 {
134         g_debug("GritsPluginMap: new");
135         GritsPluginMap *map = g_object_new(GRITS_TYPE_PLUGIN_MAP, NULL);
136         map->viewer = g_object_ref(viewer);
137
138         /* Load initial tiles */
139         gdouble lat, lon, elev;
140         grits_viewer_get_location(viewer, &lat, &lon, &elev);
141         _on_location_changed(viewer, lat, lon, elev, map);
142
143         /* Connect signals */
144         map->sigid = g_signal_connect(map->viewer, "location-changed",
145                         G_CALLBACK(_on_location_changed), map);
146
147         /* Add renderers */
148         grits_viewer_add(viewer, GRITS_OBJECT(map->tiles), GRITS_LEVEL_WORLD, FALSE);
149
150         return map;
151 }
152
153
154 /****************
155  * GObject code *
156  ****************/
157 /* Plugin init */
158 static void grits_plugin_map_plugin_init(GritsPluginInterface *iface);
159 G_DEFINE_TYPE_WITH_CODE(GritsPluginMap, grits_plugin_map, G_TYPE_OBJECT,
160                 G_IMPLEMENT_INTERFACE(GRITS_TYPE_PLUGIN,
161                         grits_plugin_map_plugin_init));
162 static void grits_plugin_map_plugin_init(GritsPluginInterface *iface)
163 {
164         g_debug("GritsPluginMap: plugin_init");
165         /* Add methods to the interface */
166 }
167 /* Class/Object init */
168 static void grits_plugin_map_init(GritsPluginMap *map)
169 {
170         g_debug("GritsPluginMap: init");
171         /* Set defaults */
172         map->threads = g_thread_pool_new(_load_tile_thread, map, 1, FALSE, NULL);
173         map->tiles = grits_tile_new(NULL, 85.0511, -85.0511, EAST, WEST);
174         map->tms   = grits_tms_new("http://tile.openstreetmap.org",
175                 "osmtile/", "png");
176         map->tiles->proj = GRITS_PROJ_MERCATOR;
177         //map->tiles = grits_tile_new(NULL, NORTH, SOUTH, EAST, WEST);
178         //map->wms   = grits_wms_new(
179         //      "http://vmap0.tiles.osgeo.org/wms/vmap0",
180         //      "basic,priroad,secroad,depthcontour,clabel,statelabel",
181         //       "image/png", "osm/", "png", TILE_WIDTH, TILE_HEIGHT);
182         g_object_ref(map->tiles);
183 }
184 static void grits_plugin_map_dispose(GObject *gobject)
185 {
186         g_debug("GritsPluginMap: dispose");
187         GritsPluginMap *map = GRITS_PLUGIN_MAP(gobject);
188         map->aborted = TRUE;
189         /* Drop references */
190         if (map->viewer) {
191                 GritsViewer *viewer = map->viewer;
192                 g_signal_handler_disconnect(viewer, map->sigid);
193                 soup_session_abort(map->tms->http->soup);
194                 //soup_session_abort(map->wms->http->soup);
195                 g_thread_pool_free(map->threads, TRUE, TRUE);
196                 map->viewer = NULL;
197                 grits_viewer_remove(viewer, GRITS_OBJECT(map->tiles));
198                 g_object_unref(map->tiles);
199                 g_object_unref(viewer);
200         }
201         G_OBJECT_CLASS(grits_plugin_map_parent_class)->dispose(gobject);
202 }
203 static void grits_plugin_map_finalize(GObject *gobject)
204 {
205         g_debug("GritsPluginMap: finalize");
206         GritsPluginMap *map = GRITS_PLUGIN_MAP(gobject);
207         /* Free data */
208         grits_tms_free(map->tms);
209         //grits_wms_free(map->wms);
210         grits_tile_free(map->tiles, NULL, map);
211         G_OBJECT_CLASS(grits_plugin_map_parent_class)->finalize(gobject);
212
213 }
214 static void grits_plugin_map_class_init(GritsPluginMapClass *klass)
215 {
216         g_debug("GritsPluginMap: class_init");
217         GObjectClass *gobject_class = (GObjectClass*)klass;
218         gobject_class->dispose  = grits_plugin_map_dispose;
219         gobject_class->finalize = grits_plugin_map_finalize;
220 }