]> git.street.me.uk Git - andy/viking.git/blame - src/vikslippymapsource.c
SF Features#116: Add an Acquire From URL option.
[andy/viking.git] / src / vikslippymapsource.c
CommitLineData
e3a90009
GB
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2/*
3 * viking
a482007a 4 * Copyright (C) 2009, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
e3a90009
GB
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 */
dfc4db8b
GB
19
20 /**
21 * SECTION:vikslippymapsource
22 * @short_description: the class for SlippyMap oriented map sources
23 *
24 * The #VikSlippyMapSource class handles slippy map oriented map sources.
25 * The related service is tile oriented, à la Google.
26 *
27 * The tiles are in 'google spherical mercator', which is
28 * basically a mercator projection that assumes a spherical earth.
29 * http://docs.openlayers.org/library/spherical_mercator.html
30 *
31 * Such service is also a type of TMS (Tile Map Service) as defined in
32 * OSGeo's wiki.
33 * http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
34 * But take care that the Y axis is inverted, ie the origin is at top-left
35 * corner.
36 * Following this specification, the protocol handled by this class
37 * follows the global-mercator profile.
38 *
39 * You can also find many interesting information on the OSM's wiki.
40 * http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
41 * http://wiki.openstreetmap.org/wiki/Setting_up_TMS
42 */
43
e3a90009
GB
44#ifdef HAVE_CONFIG_H
45#include "config.h"
46#endif
47
48#ifdef HAVE_MATH_H
49#include <math.h>
50#endif
51
52#include "globals.h"
8eb12ac6 53#include "vikslippymapsource.h"
e1dde2a6 54#include "maputils.h"
e3a90009
GB
55
56static gboolean _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest );
57static void _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest );
f66ea3ec 58
2673b29d 59static gboolean _is_direct_file_access (VikMapSource *self );
c81ded98 60static gboolean _supports_download_only_new (VikMapSource *self );
e3a90009 61
f66ea3ec
GB
62static gchar *_get_uri( VikMapSourceDefault *self, MapCoord *src );
63static gchar *_get_hostname( VikMapSourceDefault *self );
64static DownloadMapOptions *_get_download_options( VikMapSourceDefault *self );
e3a90009 65
8eb12ac6
GB
66typedef struct _VikSlippyMapSourcePrivate VikSlippyMapSourcePrivate;
67struct _VikSlippyMapSourcePrivate
68{
69 gchar *hostname;
70 gchar *url;
b529dc9c 71 DownloadMapOptions options;
2673b29d 72 gboolean is_direct_file_access;
8eb12ac6
GB
73};
74
75#define VIK_SLIPPY_MAP_SOURCE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VIK_TYPE_SLIPPY_MAP_SOURCE, VikSlippyMapSourcePrivate))
76
4e53f3dc
GB
77/* properties */
78enum
79{
80 PROP_0,
81
82 PROP_HOSTNAME,
83 PROP_URL,
c395c6a5
GB
84 PROP_REFERER,
85 PROP_FOLLOW_LOCATION,
0f08bd0d 86 PROP_CHECK_FILE_SERVER_TIME,
05dbd9ba 87 PROP_USE_ETAG,
2673b29d 88 PROP_IS_DIRECT_FILE_ACCESS,
4e53f3dc
GB
89};
90
f6411015 91G_DEFINE_TYPE (VikSlippyMapSource, vik_slippy_map_source, VIK_TYPE_MAP_SOURCE_DEFAULT);
e3a90009
GB
92
93static void
3a84e537 94vik_slippy_map_source_init (VikSlippyMapSource *self)
e3a90009 95{
9cca9d93
GB
96 /* initialize the object here */
97 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
98
99 priv->hostname = NULL;
100 priv->url = NULL;
c395c6a5
GB
101 priv->options.referer = NULL;
102 priv->options.follow_location = 0;
103 priv->options.check_file = a_check_map_file;
6693f5f9 104 priv->options.check_file_server_time = FALSE;
2673b29d
RN
105 priv->options.use_etag = FALSE;
106 priv->is_direct_file_access = FALSE;
9cca9d93
GB
107
108 g_object_set (G_OBJECT (self),
109 "tilesize-x", 256,
110 "tilesize-y", 256,
111 "drawmode", VIK_VIEWPORT_DRAWMODE_MERCATOR,
112 NULL);
e3a90009
GB
113}
114
115static void
8eb12ac6 116vik_slippy_map_source_finalize (GObject *object)
e3a90009 117{
9cca9d93
GB
118 VikSlippyMapSource *self = VIK_SLIPPY_MAP_SOURCE (object);
119 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
120
121 g_free (priv->hostname);
122 priv->hostname = NULL;
123 g_free (priv->url);
124 priv->url = NULL;
c395c6a5
GB
125 g_free (priv->options.referer);
126 priv->options.referer = NULL;
e3a90009 127
9cca9d93 128 G_OBJECT_CLASS (vik_slippy_map_source_parent_class)->finalize (object);
e3a90009
GB
129}
130
4e53f3dc
GB
131static void
132vik_slippy_map_source_set_property (GObject *object,
133 guint property_id,
134 const GValue *value,
135 GParamSpec *pspec)
136{
137 VikSlippyMapSource *self = VIK_SLIPPY_MAP_SOURCE (object);
138 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
139
140 switch (property_id)
141 {
142 case PROP_HOSTNAME:
143 g_free (priv->hostname);
144 priv->hostname = g_value_dup_string (value);
145 break;
146
147 case PROP_URL:
148 g_free (priv->url);
149 priv->url = g_value_dup_string (value);
150 break;
151
c395c6a5
GB
152 case PROP_REFERER:
153 g_free (priv->options.referer);
154 priv->options.referer = g_value_dup_string (value);
155 break;
156
157 case PROP_FOLLOW_LOCATION:
158 priv->options.follow_location = g_value_get_long (value);
159 break;
160
0f08bd0d 161 case PROP_CHECK_FILE_SERVER_TIME:
6693f5f9 162 priv->options.check_file_server_time = g_value_get_boolean (value);
0f08bd0d
GB
163 break;
164
05dbd9ba
JJ
165 case PROP_USE_ETAG:
166 priv->options.use_etag = g_value_get_boolean (value);
167 break;
168
2673b29d
RN
169 case PROP_IS_DIRECT_FILE_ACCESS:
170 priv->is_direct_file_access = g_value_get_boolean (value);
171 break;
172
4e53f3dc
GB
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
180static void
181vik_slippy_map_source_get_property (GObject *object,
182 guint property_id,
183 GValue *value,
184 GParamSpec *pspec)
185{
186 VikSlippyMapSource *self = VIK_SLIPPY_MAP_SOURCE (object);
187 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE (self);
188
189 switch (property_id)
190 {
191 case PROP_HOSTNAME:
192 g_value_set_string (value, priv->hostname);
193 break;
194
195 case PROP_URL:
196 g_value_set_string (value, priv->url);
197 break;
198
c395c6a5
GB
199 case PROP_REFERER:
200 g_value_set_string (value, priv->options.referer);
201 break;
202
203 case PROP_FOLLOW_LOCATION:
204 g_value_set_long (value, priv->options.follow_location);
205 break;
206
0f08bd0d 207 case PROP_CHECK_FILE_SERVER_TIME:
6693f5f9 208 g_value_set_boolean (value, priv->options.check_file_server_time);
0f08bd0d
GB
209 break;
210
05dbd9ba
JJ
211 case PROP_USE_ETAG:
212 g_value_set_boolean (value, priv->options.use_etag);
213 break;
214
2673b29d
RN
215 case PROP_IS_DIRECT_FILE_ACCESS:
216 g_value_set_boolean (value, priv->is_direct_file_access);
217 break;
218
4e53f3dc
GB
219 default:
220 /* We don't have any other property... */
221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
222 break;
223 }
224}
225
e3a90009 226static void
8eb12ac6 227vik_slippy_map_source_class_init (VikSlippyMapSourceClass *klass)
e3a90009
GB
228{
229 GObjectClass* object_class = G_OBJECT_CLASS (klass);
de674329 230 VikMapSourceClass* grandparent_class = VIK_MAP_SOURCE_CLASS (klass);
f66ea3ec 231 VikMapSourceDefaultClass* parent_class = VIK_MAP_SOURCE_DEFAULT_CLASS (klass);
4e53f3dc
GB
232 GParamSpec *pspec = NULL;
233
234 object_class->set_property = vik_slippy_map_source_set_property;
235 object_class->get_property = vik_slippy_map_source_get_property;
e3a90009
GB
236
237 /* Overiding methods */
de674329
RN
238 grandparent_class->coord_to_mapcoord = _coord_to_mapcoord;
239 grandparent_class->mapcoord_to_center_coord = _mapcoord_to_center_coord;
2673b29d 240 grandparent_class->is_direct_file_access = _is_direct_file_access;
de674329 241 grandparent_class->supports_download_only_new = _supports_download_only_new;
f66ea3ec
GB
242
243 parent_class->get_uri = _get_uri;
244 parent_class->get_hostname = _get_hostname;
245 parent_class->get_download_options = _get_download_options;
4e53f3dc
GB
246
247 pspec = g_param_spec_string ("hostname",
248 "Hostname",
249 "The hostname of the map server",
250 "<no-set>" /* default value */,
9f58c4b4 251 G_PARAM_READWRITE);
4e53f3dc
GB
252 g_object_class_install_property (object_class, PROP_HOSTNAME, pspec);
253
254 pspec = g_param_spec_string ("url",
255 "URL",
256 "The template of the tiles' URL",
257 "<no-set>" /* default value */,
9f58c4b4 258 G_PARAM_READWRITE);
4e53f3dc 259 g_object_class_install_property (object_class, PROP_URL, pspec);
c395c6a5
GB
260
261 pspec = g_param_spec_string ("referer",
262 "Referer",
263 "The REFERER string to use in HTTP request",
264 NULL /* default value */,
265 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
266 g_object_class_install_property (object_class, PROP_REFERER, pspec);
8eb12ac6 267
c395c6a5
GB
268 pspec = g_param_spec_long ("follow-location",
269 "Follow location",
270 "Specifies the number of retries to follow a redirect while downloading a page",
271 0 /* minimum value */,
272 G_MAXLONG /* maximum value */,
273 0 /* default value */,
274 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
275 g_object_class_install_property (object_class, PROP_FOLLOW_LOCATION, pspec);
0f08bd0d 276
6693f5f9
GB
277 pspec = g_param_spec_boolean ("check-file-server-time",
278 "Check file server time",
279 "Age of current cache before redownloading tile",
280 FALSE /* default value */,
281 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
0f08bd0d 282 g_object_class_install_property (object_class, PROP_CHECK_FILE_SERVER_TIME, pspec);
c395c6a5 283
05dbd9ba
JJ
284 pspec = g_param_spec_boolean ("use-etag",
285 "Use etag values with server",
286 "Store etag in a file, and send it to server to check if we have the latest file",
287 FALSE /* default value */,
288 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
289 g_object_class_install_property (object_class, PROP_USE_ETAG, pspec);
290
2673b29d
RN
291 pspec = g_param_spec_boolean ("use-direct-file-access",
292 "Use direct file access",
293 "Use direct file access to OSM like tile images - no need for a webservice",
294 FALSE /* default value */,
295 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
296 g_object_class_install_property (object_class, PROP_IS_DIRECT_FILE_ACCESS, pspec);
297
8eb12ac6
GB
298 g_type_class_add_private (klass, sizeof (VikSlippyMapSourcePrivate));
299
300 object_class->finalize = vik_slippy_map_source_finalize;
e3a90009
GB
301}
302
cf65dac0 303static gboolean
2673b29d
RN
304_is_direct_file_access (VikMapSource *self)
305{
306 g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), FALSE);
307
308 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
309
310 return priv->is_direct_file_access;
311}
312
cf65dac0 313static gboolean
c81ded98 314_supports_download_only_new (VikMapSource *self)
0f08bd0d 315{
c81ded98 316 g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), FALSE);
0f08bd0d 317
c81ded98 318 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
0f08bd0d 319
c81ded98 320 return priv->options.check_file_server_time || priv->options.use_etag;
0f08bd0d 321}
f66ea3ec 322
e3a90009
GB
323static gboolean
324_coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
325{
326 g_assert ( src->mode == VIK_COORD_LATLON );
327
328 if ( xzoom != yzoom )
329 return FALSE;
330
e1dde2a6 331 dest->scale = map_utils_mpp_to_scale ( xzoom );
e3a90009
GB
332 if ( dest->scale == 255 )
333 return FALSE;
334
e1dde2a6
RN
335 dest->x = (src->east_west + 180) / 360 * VIK_GZ(17) / xzoom;
336 dest->y = (180 - MERCLAT(src->north_south)) / 360 * VIK_GZ(17) / xzoom;
e3a90009
GB
337 dest->z = 0;
338
339 return TRUE;
340}
341
342static void
343_mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest )
344{
d1302dec
JJ
345 gdouble socalled_mpp;
346 if (src->scale >= 0)
e1dde2a6 347 socalled_mpp = VIK_GZ(src->scale);
d1302dec 348 else
e1dde2a6 349 socalled_mpp = 1.0/VIK_GZ(-src->scale);
e3a90009 350 dest->mode = VIK_COORD_LATLON;
e1dde2a6
RN
351 dest->east_west = ((src->x+0.5) / VIK_GZ(17) * socalled_mpp * 360) - 180;
352 dest->north_south = DEMERCLAT(180 - ((src->y+0.5) / VIK_GZ(17) * socalled_mpp * 360));
e3a90009
GB
353}
354
8eb12ac6 355static gchar *
f66ea3ec 356_get_uri( VikMapSourceDefault *self, MapCoord *src )
8eb12ac6
GB
357{
358 g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), NULL);
359
360 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
361 gchar *uri = g_strdup_printf (priv->url, 17 - src->scale, src->x, src->y);
362 return uri;
363}
364
365static gchar *
f66ea3ec 366_get_hostname( VikMapSourceDefault *self )
8eb12ac6
GB
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 return g_strdup( priv->hostname );
372}
373
b529dc9c 374static DownloadMapOptions *
f66ea3ec 375_get_download_options( VikMapSourceDefault *self )
8eb12ac6
GB
376{
377 g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), NULL);
378
c395c6a5
GB
379 VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
380 return &(priv->options);
8eb12ac6
GB
381}
382
383VikSlippyMapSource *
d7e495b2 384vik_slippy_map_source_new_with_id (guint16 id, const gchar *label, const gchar *hostname, const gchar *url)
8eb12ac6 385{
4e53f3dc 386 return g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
db03733a 387 "id", id, "label", label, "hostname", hostname, "url", url, NULL);
c395c6a5 388}