]> git.street.me.uk Git - andy/viking.git/blob - src/google.c
No longer provide support for google satellite maps.
[andy/viking.git] / src / google.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtk.h>
30 #include <math.h>
31 #include <string.h>
32 #include "coords.h"
33 #include "vikcoord.h"
34 #include "mapcoord.h"
35 #include "download.h"
36 #include "curl_download.h"
37 #include "globals.h"
38 #include "google.h"
39 #include "vikmapslayer.h"
40
41
42 static int google_download ( MapCoord *src, const gchar *dest_fn );
43 static int google_trans_download ( MapCoord *src, const gchar *dest_fn );
44 static int google_terrain_download ( MapCoord *src, const gchar *dest_fn );
45 static void google_mapcoord_to_center_coord ( MapCoord *src, VikCoord *dest );
46 static gboolean google_coord_to_mapcoord ( const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest );
47
48 static DownloadOptions google_options = { "http://maps.google.com/", 0, a_check_map_file };
49
50 void google_init () {
51   VikMapsLayer_MapType google_1 = { 7, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_download };
52   VikMapsLayer_MapType google_2 = { 10, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_trans_download };
53   VikMapsLayer_MapType google_4 = { 16, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_terrain_download };
54
55   maps_layer_register_type(_("Google Street Maps"), 7, &google_1);
56   maps_layer_register_type(_("Transparent Google Maps"), 10, &google_2);
57   maps_layer_register_type(_("Google Terrain Maps"), 16, &google_4);
58 }
59
60 /* 1 << (x) is like a 2**(x) */
61 #define GZ(x) ((1<<x))
62
63 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),
64                                            GZ(10), GZ(11), GZ(12), GZ(13), GZ(14), GZ(15), GZ(16), GZ(17) };
65
66 static const gint num_scales = (sizeof(scale_mpps) / sizeof(scale_mpps[0]));
67
68 #define ERROR_MARGIN 0.01
69 guint8 google_zoom ( gdouble mpp ) {
70   gint i;
71   for ( i = 0; i < num_scales; i++ ) {
72     if ( ABS(scale_mpps[i] - mpp) < ERROR_MARGIN )
73       return i;
74   }
75   return 255;
76 }
77
78 typedef enum {
79         TYPE_GOOGLE_MAPS = 0,
80         TYPE_GOOGLE_TRANS,
81         TYPE_GOOGLE_TERRAIN,
82
83         TYPE_GOOGLE_NUM
84 } GoogleType;
85
86 static gchar *parse_version_number(gchar *text)
87 {
88   int i;
89   gchar *vers;
90   gchar *s = text;
91
92   for (i = 0; (s[i] != '\\') && (i < 8); i++)
93     ;
94   if (s[i] != '\\') {
95     return NULL;
96   }
97
98   return vers = g_strndup(s, i);
99 }
100
101 static const gchar *google_version_number(MapCoord *mapcoord, GoogleType google_type)
102 {
103   static gboolean first = TRUE;
104   static char *vers[] = { "w2.80", "w2t.80", "w2p.81"};
105   FILE *tmp_file;
106   int tmp_fd;
107   gchar *tmpname;
108   gchar *uri;
109   VikCoord coord;
110   gchar coord_north_south[G_ASCII_DTOSTR_BUF_SIZE], coord_east_west[G_ASCII_DTOSTR_BUF_SIZE];
111   gchar *text, *pat, *beg;
112   GMappedFile *mf;
113   gsize len;
114   gchar *gvers, *tvers, *terrvers, *tmpvers;
115   static DownloadOptions dl_options = { "http://maps.google.com/", 0, a_check_map_file };
116   static const char *gvers_pat = "http://mt0.google.com/mt";
117
118   g_assert(google_type < TYPE_GOOGLE_NUM);
119
120   if (!first)
121     return (vers[google_type]);
122
123
124   first = FALSE;
125   gvers = tvers = terrvers = NULL;
126   if ((tmp_fd = g_file_open_tmp ("vikgvers.XXXXXX", &tmpname, NULL)) == -1) {
127     g_critical(_("couldn't open temp file %s"), tmpname);
128     exit(1);
129   } 
130
131   google_mapcoord_to_center_coord(mapcoord, &coord);
132   uri = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s,%s",
133                         g_ascii_dtostr (coord_north_south, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) coord.north_south),
134                         g_ascii_dtostr (coord_east_west, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) coord.east_west));
135   tmp_file = fdopen(tmp_fd, "r+");
136
137   if (curl_download_uri(uri, tmp_file, &dl_options)) {  /* error */
138     g_warning(_("Failed downloading %s"), tmpname);
139   } else {
140     if ((mf = g_mapped_file_new(tmpname, FALSE, NULL)) == NULL) {
141       g_critical(_("couldn't map temp file"));
142       exit(1);
143     }
144     len = g_mapped_file_get_length(mf);
145     text = g_mapped_file_get_contents(mf);
146
147     if ((beg = g_strstr_len(text, len, "GLoadApi")) == NULL) {
148       g_warning(_("Failed fetching Google numbers (\"GLoadApi\" not found)"));
149       goto failed;
150     }
151
152     pat = beg;
153     while (!gvers || !tvers ||!terrvers) {
154       if ((pat = g_strstr_len(pat, &text[len] - pat, gvers_pat)) != NULL) {
155         pat += strlen(gvers_pat);
156         if ((pat[0] != '/' && pat[0] != '?') ||
157              pat[1] != 'v' || pat[2] != '\\' ||
158              pat[3] != 'x' || pat[4] != '3' || pat[5] != 'd')
159           continue;
160         pat += 6;
161         if ((tmpvers = parse_version_number(pat)) != NULL) {
162           if (strstr(tmpvers, "t."))
163             tvers = tmpvers;
164           else if (strstr(tmpvers, "p."))
165             terrvers = tmpvers;
166           else
167             gvers = tmpvers;
168         }
169       }
170       else
171         break;
172     }
173
174     if (gvers && tvers && terrvers) {
175       vers[TYPE_GOOGLE_MAPS] = gvers;
176       vers[TYPE_GOOGLE_TRANS] = tvers;
177       vers[TYPE_GOOGLE_TERRAIN] = terrvers;
178     }
179     else
180       g_warning(_("Failed getting google version numbers"));
181
182     if (gvers)
183       fprintf(stderr, "DEBUG gvers=%s\n", gvers);
184     if (tvers)
185       fprintf(stderr, "DEBUG tvers=%s\n", tvers);
186     if (terrvers)
187       fprintf(stderr, "DEBUG terrvers=%s\n", terrvers);
188
189 failed:
190     g_mapped_file_free(mf);
191   }
192
193   fclose(tmp_file);
194   tmp_file = NULL;
195   g_free(tmpname);
196   g_free (uri);
197   return (vers[google_type]);
198 }
199
200 gboolean google_coord_to_mapcoord ( const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
201 {
202   g_assert ( src->mode == VIK_COORD_LATLON );
203
204   if ( xzoom != yzoom )
205     return FALSE;
206
207   dest->scale = google_zoom ( xzoom );
208   if ( dest->scale == 255 )
209     return FALSE;
210
211   dest->x = (src->east_west + 180) / 360 * GZ(17) / xzoom;
212   dest->y = (180 - MERCLAT(src->north_south)) / 360 * GZ(17) / xzoom;
213   dest->z = 0;
214
215   return TRUE;
216 }
217
218 void google_mapcoord_to_center_coord ( MapCoord *src, VikCoord *dest )
219 {
220   gdouble socalled_mpp = GZ(src->scale);
221   dest->mode = VIK_COORD_LATLON;
222   dest->east_west = ((src->x+0.5) / GZ(17) * socalled_mpp * 360) - 180;
223   dest->north_south = DEMERCLAT(180 - ((src->y+0.5) / GZ(17) * socalled_mpp * 360));
224 }
225
226 static int real_google_download ( MapCoord *src, const gchar *dest_fn, const char *verstr )
227 {
228    int res;
229    gchar *uri = g_strdup_printf ( "/mt?n=404&v=%s&x=%d&y=%d&zoom=%d", verstr, src->x, src->y, src->scale );
230    res = a_http_download_get_url ( "mt.google.com", uri, dest_fn, &google_options );
231    g_free ( uri );
232    return res;
233 }
234
235 static int google_download ( MapCoord *src, const gchar *dest_fn )
236 {
237    const gchar *vers_str = google_version_number(src, TYPE_GOOGLE_MAPS);
238    return(real_google_download ( src, dest_fn, vers_str ));
239 }
240
241 static int google_trans_download ( MapCoord *src, const gchar *dest_fn )
242 {
243    const gchar *vers_str = google_version_number(src, TYPE_GOOGLE_TRANS);
244    return(real_google_download ( src, dest_fn, vers_str ));
245 }
246
247 static int google_terrain_download ( MapCoord *src, const gchar *dest_fn )
248 {
249    const gchar *vers_str = google_version_number(src, TYPE_GOOGLE_TERRAIN);
250    return(real_google_download ( src, dest_fn, vers_str ));
251 }