]> git.street.me.uk Git - andy/viking.git/blob - src/vikslippymapsource.c
Add and use preference for speed units.
[andy/viking.git] / src / vikslippymapsource.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * viking
4  * Copyright (C) Guilhem Bonnefille 2009 <guilhem.bonnefille@gmail.com>
5  * 
6  * viking is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  * 
11  * viking is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #ifdef HAVE_MATH_H
24 #include <math.h>
25 #endif
26
27 #include "globals.h"
28 #include "vikslippymapsource.h"
29
30 static gboolean _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest );
31 static void _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest );
32 static int _download ( VikMapSource *self, MapCoord *src, const gchar *dest_fn, void *handle );
33 static void * _download_handle_init ( VikMapSource *self);
34 static void _download_handle_cleanup ( VikMapSource *self, void *handle);
35 static gboolean _supports_if_modified_since (VikMapSource *self );
36
37 static gchar *_get_uri( VikSlippyMapSource *self, MapCoord *src );
38 static gchar *_get_hostname( VikSlippyMapSource *self );
39 static DownloadOptions *_get_download_options( VikSlippyMapSource *self );
40
41 typedef struct _VikSlippyMapSourcePrivate VikSlippyMapSourcePrivate;
42 struct _VikSlippyMapSourcePrivate
43 {
44   gchar *hostname;
45   gchar *url;
46   DownloadOptions options;
47 };
48
49 #define VIK_SLIPPY_MAP_SOURCE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), VIK_TYPE_SLIPPY_MAP_SOURCE, VikSlippyMapSourcePrivate))
50
51 /* properties */
52 enum
53 {
54   PROP_0,
55
56   PROP_HOSTNAME,
57   PROP_URL,
58   PROP_REFERER,
59   PROP_FOLLOW_LOCATION,
60   PROP_CHECK_FILE_SERVER_TIME,
61 };
62
63 G_DEFINE_TYPE_EXTENDED (VikSlippyMapSource, vik_slippy_map_source, VIK_TYPE_MAP_SOURCE_DEFAULT, (GTypeFlags)0,);
64
65 static void
66 vik_slippy_map_source_init (VikSlippyMapSource *self)
67 {
68   /* initialize the object here */
69   VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
70
71   priv->hostname = NULL;
72   priv->url = NULL;
73   priv->options.referer = NULL;
74   priv->options.follow_location = 0;
75   priv->options.check_file = a_check_map_file;
76   priv->options.check_file_server_time = FALSE;
77
78   g_object_set (G_OBJECT (self),
79                 "tilesize-x", 256,
80                 "tilesize-y", 256,
81                 "drawmode", VIK_VIEWPORT_DRAWMODE_MERCATOR,
82                 NULL);
83 }
84
85 static void
86 vik_slippy_map_source_finalize (GObject *object)
87 {
88   VikSlippyMapSource *self = VIK_SLIPPY_MAP_SOURCE (object);
89   VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
90
91   g_free (priv->hostname);
92   priv->hostname = NULL;
93   g_free (priv->url);
94   priv->url = NULL;
95   g_free (priv->options.referer);
96   priv->options.referer = NULL;
97
98   G_OBJECT_CLASS (vik_slippy_map_source_parent_class)->finalize (object);
99 }
100
101 static void
102 vik_slippy_map_source_set_property (GObject      *object,
103                                     guint         property_id,
104                                     const GValue *value,
105                                     GParamSpec   *pspec)
106 {
107   VikSlippyMapSource *self = VIK_SLIPPY_MAP_SOURCE (object);
108   VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
109
110   switch (property_id)
111     {
112     case PROP_HOSTNAME:
113       g_free (priv->hostname);
114       priv->hostname = g_value_dup_string (value);
115       break;
116
117     case PROP_URL:
118       g_free (priv->url);
119       priv->url = g_value_dup_string (value);
120       break;
121
122     case PROP_REFERER:
123       g_free (priv->options.referer);
124       priv->options.referer = g_value_dup_string (value);
125       break;
126
127     case PROP_FOLLOW_LOCATION:
128       priv->options.follow_location = g_value_get_long (value);
129       break;
130
131     case PROP_CHECK_FILE_SERVER_TIME:
132       priv->options.check_file_server_time = g_value_get_boolean (value);
133       break;
134
135     default:
136       /* We don't have any other property... */
137       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
138       break;
139     }
140 }
141
142 static void
143 vik_slippy_map_source_get_property (GObject    *object,
144                                     guint       property_id,
145                                     GValue     *value,
146                                     GParamSpec *pspec)
147 {
148   VikSlippyMapSource *self = VIK_SLIPPY_MAP_SOURCE (object);
149   VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
150
151   switch (property_id)
152     {
153     case PROP_HOSTNAME:
154       g_value_set_string (value, priv->hostname);
155       break;
156
157     case PROP_URL:
158       g_value_set_string (value, priv->url);
159       break;
160
161     case PROP_REFERER:
162       g_value_set_string (value, priv->options.referer);
163       break;
164
165     case PROP_FOLLOW_LOCATION:
166       g_value_set_long (value, priv->options.follow_location);
167       break;
168
169     case PROP_CHECK_FILE_SERVER_TIME:
170       g_value_set_boolean (value, priv->options.check_file_server_time);
171       break;
172           
173     default:
174       /* We don't have any other property... */
175       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
176       break;
177     }
178 }
179
180 static void
181 vik_slippy_map_source_class_init (VikSlippyMapSourceClass *klass)
182 {
183         GObjectClass* object_class = G_OBJECT_CLASS (klass);
184         VikMapSourceClass* parent_class = VIK_MAP_SOURCE_CLASS (klass);
185         GParamSpec *pspec = NULL;
186                 
187         object_class->set_property = vik_slippy_map_source_set_property;
188     object_class->get_property = vik_slippy_map_source_get_property;
189
190         /* Overiding methods */
191         parent_class->coord_to_mapcoord =        _coord_to_mapcoord;
192         parent_class->mapcoord_to_center_coord = _mapcoord_to_center_coord;
193         parent_class->download =                 _download;
194         parent_class->download_handle_init =     _download_handle_init;
195         parent_class->download_handle_cleanup =  _download_handle_cleanup;
196         parent_class->supports_if_modified_since = _supports_if_modified_since;
197         
198         /* Default implementation of methods */
199         klass->get_uri = _get_uri;
200         klass->get_hostname = _get_hostname;
201         klass->get_download_options = _get_download_options;
202
203         pspec = g_param_spec_string ("hostname",
204                                      "Hostname",
205                                      "The hostname of the map server",
206                                      "<no-set>" /* default value */,
207                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
208         g_object_class_install_property (object_class, PROP_HOSTNAME, pspec);
209
210         pspec = g_param_spec_string ("url",
211                                      "URL",
212                                      "The template of the tiles' URL",
213                                      "<no-set>" /* default value */,
214                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
215         g_object_class_install_property (object_class, PROP_URL, pspec);
216
217         pspec = g_param_spec_string ("referer",
218                                      "Referer",
219                                      "The REFERER string to use in HTTP request",
220                                      NULL /* default value */,
221                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
222         g_object_class_install_property (object_class, PROP_REFERER, pspec);
223         
224         pspec = g_param_spec_long ("follow-location",
225                                    "Follow location",
226                                "Specifies the number of retries to follow a redirect while downloading a page",
227                                0  /* minimum value */,
228                                G_MAXLONG /* maximum value */,
229                                0  /* default value */,
230                                G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
231         g_object_class_install_property (object_class, PROP_FOLLOW_LOCATION, pspec);
232         
233         pspec = g_param_spec_boolean ("check-file-server-time",
234                                       "Check file server time",
235                                   "Age of current cache before redownloading tile",
236                                   FALSE  /* default value */,
237                                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
238         g_object_class_install_property (object_class, PROP_CHECK_FILE_SERVER_TIME, pspec);
239
240         g_type_class_add_private (klass, sizeof (VikSlippyMapSourcePrivate));
241         
242         object_class->finalize = vik_slippy_map_source_finalize;
243 }
244
245 /* 1 << (x) is like a 2**(x) */
246 #define GZ(x) ((1<<x))
247
248 static const gdouble scale_mpps[] = { GZ(0), GZ(1), GZ(2), GZ(3), GZ(4), GZ(5), GZ(6), GZ(7), GZ(8), GZ(9),
249                                            GZ(10), GZ(11), GZ(12), GZ(13), GZ(14), GZ(15), GZ(16), GZ(17) };
250
251 static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0]));
252
253 #define ERROR_MARGIN 0.01
254 static guint8 slippy_zoom ( gdouble mpp ) {
255   gint i;
256   for ( i = 0; i < num_scales; i++ ) {
257     if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN )
258       return i;
259   }
260   return 255;
261 }
262
263 gchar *
264 vik_slippy_map_source_get_uri( VikSlippyMapSource *self, MapCoord *src )
265 {
266         VikSlippyMapSourceClass *klass;
267         g_return_val_if_fail (self != NULL, 0);
268         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE (self), 0);
269         klass = VIK_SLIPPY_MAP_SOURCE_GET_CLASS(self);
270
271         g_return_val_if_fail (klass->get_uri != NULL, 0);
272
273         return (*klass->get_uri)(self, src);
274 }
275
276 gchar *
277 vik_slippy_map_source_get_hostname( VikSlippyMapSource *self )
278 {
279         VikSlippyMapSourceClass *klass;
280         g_return_val_if_fail (self != NULL, 0);
281         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE (self), 0);
282         klass = VIK_SLIPPY_MAP_SOURCE_GET_CLASS(self);
283
284         g_return_val_if_fail (klass->get_hostname != NULL, 0);
285
286         return (*klass->get_hostname)(self);
287 }
288
289 DownloadOptions *
290 vik_slippy_map_source_get_download_options( VikSlippyMapSource *self )
291 {
292         VikSlippyMapSourceClass *klass;
293         g_return_val_if_fail (self != NULL, 0);
294         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE (self), 0);
295         klass = VIK_SLIPPY_MAP_SOURCE_GET_CLASS(self);
296
297         g_return_val_if_fail (klass->get_download_options != NULL, 0);
298
299         return (*klass->get_download_options)(self);
300 }
301
302 gboolean
303 _supports_if_modified_since (VikMapSource *self)
304 {
305         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), FALSE);
306         
307     VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
308         
309         return priv->options.check_file_server_time;
310 }
311 static gboolean
312 _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
313 {
314   g_assert ( src->mode == VIK_COORD_LATLON );
315
316   if ( xzoom != yzoom )
317     return FALSE;
318
319   dest->scale = slippy_zoom ( xzoom );
320   if ( dest->scale == 255 )
321     return FALSE;
322
323   dest->x = (src->east_west + 180) / 360 * GZ(17) / xzoom;
324   dest->y = (180 - MERCLAT(src->north_south)) / 360 * GZ(17) / xzoom;
325   dest->z = 0;
326
327   return TRUE;
328 }
329
330 static void
331 _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest )
332 {
333   gdouble socalled_mpp = GZ(src->scale);
334   dest->mode = VIK_COORD_LATLON;
335   dest->east_west = ((src->x+0.5) / GZ(17) * socalled_mpp * 360) - 180;
336   dest->north_south = DEMERCLAT(180 - ((src->y+0.5) / GZ(17) * socalled_mpp * 360));
337 }
338
339 static int
340 _download ( VikMapSource *self, MapCoord *src, const gchar *dest_fn, void *handle )
341 {
342    int res;
343    gchar *uri = vik_slippy_map_source_get_uri(VIK_SLIPPY_MAP_SOURCE(self), src);
344    gchar *host = vik_slippy_map_source_get_hostname(VIK_SLIPPY_MAP_SOURCE(self));
345    DownloadOptions *options = vik_slippy_map_source_get_download_options(VIK_SLIPPY_MAP_SOURCE(self));
346    res = a_http_download_get_url ( host, uri, dest_fn, options, handle );
347    g_free ( uri );
348    g_free ( host );
349    return res;
350 }
351
352 static void *
353 _download_handle_init ( VikMapSource *self )
354 {
355    return a_download_handle_init ();
356 }
357
358
359 static void
360 _download_handle_cleanup ( VikMapSource *self, void *handle )
361 {
362    return a_download_handle_cleanup ( handle );
363 }
364
365 static gchar *
366 _get_uri( VikSlippyMapSource *self, MapCoord *src )
367 {
368         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), NULL);
369         
370     VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
371         gchar *uri = g_strdup_printf (priv->url, 17 - src->scale, src->x, src->y);
372         return uri;
373
374
375 static gchar *
376 _get_hostname( VikSlippyMapSource *self )
377 {
378         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), NULL);
379         
380     VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
381         return g_strdup( priv->hostname );
382 }
383
384 static DownloadOptions *
385 _get_download_options( VikSlippyMapSource *self )
386 {
387         g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), NULL);
388         
389         VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
390         return &(priv->options);
391 }
392
393 VikSlippyMapSource *
394 vik_slippy_map_source_new_with_id (guint8 id, const gchar *label, const gchar *hostname, const gchar *url)
395 {
396         return g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
397                             "id", id, "label", label, "hostname", hostname, "url", url, NULL);
398 }