Fix a crash
[framework/location/libdecarta.git] / elm_module / decarta.c
1 /*
2  * libdecarta
3  *
4  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Yunhan Kim <yhan.kim@samsung.com>,
7  *          Genie Kim <daejins.kim@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <Elementary.h>
23 #include <Eina.h>
24 #include <glib.h>
25 #include <math.h>
26
27 #include "decarta.h"
28
29 #define ZOOM_MIN 0
30 #define ZOOM_MAX 18
31
32 #ifdef M_PI
33         #undef M_PI
34 #endif
35 #define M_PI 3.1415926535897932384626433832795
36 #define DECARTA_URL_LENGTH 512
37
38 static Eina_Bool init = EINA_FALSE;
39 static Evas_Object *init_obj = NULL;
40 static char source_url[ZOOM_MAX+1][PATH_MAX];
41 static int source_req_done[ZOOM_MAX+1];
42 static Eina_Bool decarta_init = EINA_FALSE;
43
44 typedef struct _Grid_Pos
45 {
46    double lon;
47    double lat;
48 } Grid_Pos;
49
50 static Eina_Bool url_fixed[ZOOM_MAX + 1] = {EINA_FALSE};
51 static Grid_Pos map_center[ZOOM_MAX + 1] =
52 {
53    {-180.000000,85.084059},
54    {-90.000000,66.653476},
55    {-135.000000,79.242052},
56    {-174.375000,84.577645},
57    {-168.750000,84.019227},
58    {-174.375000,84.577645},
59    {-177.187500,84.837041},
60    {-178.593750,84.962060},
61    {-179.296875,85.023432},
62    {-179.648438,85.053838},
63    {-179.824219,85.068972},
64    {-179.912109,85.076521},
65    {-179.956055,85.080292},
66    {-179.978027,85.082176},
67    {-179.989014,85.083117},
68    {-179.994507,85.083588},
69    {-179.997253,85.083824},
70    {-179.998627,85.083941},
71    {-179.999313,85.084000}};
72 /*   {-179.999657,85.084030},
73    {-179.999828,85.084044}};*/
74
75 static Grid_Pos map_init[ZOOM_MAX+1] =
76 {
77    {-180.000000,0.000000 },
78    {-180.000000,66.653476},
79    {-180.000000,79.242052},
80    {-180.000000,82.724733},
81    {-180.000000,84.019227},
82    {-180.000000,84.577645},
83    {-180.000000,84.837041},
84    {-180.000000,84.962060},
85    {-180.000000,85.023432},
86    {-180.000000,85.053838},
87    {-180.000000,85.068972},
88    {-180.000000,85.076521},
89    {-180.000000,85.080292},
90    {-180.000000,85.082176},
91    {-180.000000,85.083117},
92    {-180.000000,85.083588},
93    {-180.000000,85.083824},
94    {-180.000000,85.083941},
95    {-180.000000,85.084000}};
96 /*   {-180.000000,85.084030},
97    {-180.000000,85.084044}};*/
98
99 static void map_callback(DecartaError error, const DecartaMap *map, void *data)
100 {
101         int idx;
102         double lon, lat;
103         int zoom = (int)data;
104
105         if ((error == DECARTA_ERROR_NONE) && (map) && (map->tile_url)) {
106                 source_url[zoom][DECARTA_URL_LENGTH - 1] = '\0';
107                 url_fixed[zoom] = EINA_TRUE;
108                 strncpy(source_url[zoom], map->tile_url, DECARTA_URL_LENGTH);
109         }
110
111         if (strlen(source_url[zoom]) == 0 || error != DECARTA_ERROR_NONE) {
112                 g_debug("map_callback() failed: zoom[%d], error[%d]", zoom, error);
113                 source_req_done[zoom] = -1;
114         } else {
115                 g_debug("map_callback() success: zoom[%d], error[%d]", zoom, error);
116                 source_req_done[zoom] = 1;
117         }
118
119         for (idx = ZOOM_MIN; idx <= ZOOM_MAX; idx++) {
120                 if (source_req_done[idx] <= 0) {
121                         break;
122                 }
123                 if (idx == ZOOM_MAX) {
124                         init = EINA_TRUE;
125                 }
126         }
127
128         if ((init) && (init_obj)) {
129                 init = EINA_FALSE;
130                 elm_map_region_get(init_obj, &lon, &lat);
131                 elm_map_region_bring_in(init_obj, lon - 0.00001, lat - 0.00001);
132                 elm_map_region_show(init_obj, lon, lat);
133         }
134 }
135
136 static void map_request(int zoom)
137 {
138         strncpy(source_url[zoom], "", 1);
139
140         int re = 0;
141         DecartaPosition *position = decarta_position_new (map_init[zoom].lat, map_init[zoom].lon);
142         re = decarta_search_map_async(position, zoom, &map_callback, (void*)zoom);
143         if (0 != re) {
144                 g_debug("decarta_search_map_async failed!!!, re[%d]\n", re);
145                 decarta_init = EINA_FALSE;
146         } else {
147                 decarta_init = EINA_TRUE;
148         }
149         decarta_position_free(position);
150 }
151
152 static double mercator_unproject(double t)
153 {
154         return ((double)(M_PI) / 2.0) - 2.0 * atan(t);
155 }
156
157 static double find_rad_phi(double phi, double t)
158 {
159         double ecc = 0.08181919084262157;
160         double eSinPhi = ecc * sin(phi);
161
162         double precalculate = t * pow(((1 - eSinPhi) / (1 + eSinPhi)), (ecc / 2));
163         double result = (M_PI / 2) - (2 * (atan(precalculate)));
164
165         return result;
166 }
167
168 EAPI char *map_module_source_name_get(void)
169 {
170         return strdup("Decarta Normal");
171 }
172
173 EAPI int map_module_tile_zoom_min_get(void)
174 {
175         return 0;
176 }
177
178 EAPI int map_module_tile_zoom_max_get(void)
179 {
180         return 18;
181 }
182
183 EAPI char *map_module_tile_url_get(Evas_Object *obj, int x, int y, int zoom)
184 {
185         init_obj = obj;
186
187         if (source_req_done[zoom] != 1) {
188                 g_debug("source_req_done[%d] != 1 \n", zoom);
189                 return strdup("");
190         }
191
192         if (strlen(source_url[zoom])) {
193                 char *n, *nn, *e, *ee;
194                 char strn[10], stre[10];
195                 char buf[PATH_MAX] = {'\0'};
196                 char buf2[PATH_MAX] = {'\0'};
197                 char _source_url[PATH_MAX] = {'\0'};
198
199                 strn[0]=0;
200                 stre[0]=0;
201                 buf2[0]=0;
202
203                 strncpy(_source_url, source_url[zoom], PATH_MAX - 1);
204                 n = strstr(_source_url, "&N=");
205                 nn = strstr(n+1, "&");
206                 if (nn==NULL) {
207                         nn = _source_url + strlen(_source_url);
208                 }
209
210                 e = strstr(_source_url, "&E=");
211                 ee = strstr(e+1, "&");
212                 if (ee==NULL) {
213                         ee = _source_url + strlen(_source_url);
214                 }
215
216                 strncat(strn, n + 3, nn - n - 3);
217                 strncat(stre, e + 3, ee - e - 3);
218
219                 strncat(buf2, _source_url, n - _source_url);
220                 snprintf(buf, PATH_MAX, "%s&N=%d&E=%d", buf2, atoi(strn) - y, atoi(stre) + x);
221                 return strdup(buf);
222         }
223
224         return strdup("");
225 }
226
227 EAPI double map_module_tile_scale_get(const Evas_Object *obj, double lon, double lat, int zoom)
228 {
229         return 0;
230 }
231
232 EAPI int map_module_route_source_get(void)
233 {
234         return 0;
235 }
236
237 EAPI char *map_module_route_url_get(const Evas_Object *obj,
238                                         const char *type_name,
239                                         int method,
240                                         double flon,
241                                         double flat,
242                                         double tlon,
243                                         double tlat)
244 {
245         return strdup("");
246 }
247
248 EAPI char *map_module_name_url_get(Evas_Object *obj, int method, char *name, double lon, double lat)
249 {
250         return strdup("");
251 }
252
253 EAPI Eina_Bool map_module_tile_geo_to_coord(const Evas_Object *obj,
254                                                         int zoom,
255                                                         double lon,
256                                                         double lat,
257                                                         int size,
258                                                         int *x,
259                                                         int *y)
260 {
261         if (x) {
262                 *x = floor((lon + 180.0) / 360.0 * size);
263         }
264
265         double radLat = (lat * (2.0 * M_PI)) / 360.0;
266         double ecc = 0.08181919084262157;
267
268         double sinPhi = sin(radLat);
269         double eSinPhi = ecc * sinPhi;
270
271         double pw = pow((1.0 - eSinPhi) / (1.0 + eSinPhi), ecc);
272         double retVal = log(((1.0 + sinPhi) / (1.0 - sinPhi)) * pw) / 2.0;
273
274         double y1 = retVal / (2 * M_PI / (double)size);
275
276         double real_zoom = log2(size/256.0);
277         int floored_zoom = floor(real_zoom);
278
279         if (floored_zoom >= ZOOM_MAX) {
280                 lat = map_center[ZOOM_MAX].lat;
281         } else {
282                 lat =  map_center[floored_zoom].lat + (map_center[floored_zoom + 1].lat - map_center[floored_zoom].lat) * (real_zoom - floored_zoom);
283         }
284
285         radLat = (lat * (2.0 * M_PI)) / 360.0;
286         ecc = 0.08181919084262157;
287
288         sinPhi = sin(radLat);
289         eSinPhi = ecc * sinPhi;
290
291         pw = pow((1.0 - eSinPhi) / (1.0 + eSinPhi), ecc);
292         retVal = log(((1.0 + sinPhi) / (1.0 - sinPhi)) * pw) / 2.0;
293
294         double y2 = retVal / (2 * M_PI / (double)size);
295
296         if (y) {
297                 *y = floor(y2-y1) + 128;
298         }
299
300         return EINA_TRUE;
301 }
302
303 EAPI Eina_Bool map_module_tile_coord_to_geo(const Evas_Object *obj,
304                                                         int zoom,
305                                                         int x,
306                                                         int y,
307                                                         int size,
308                                                         double *lon,
309                                                         double *lat)
310 {
311         if (lon) {
312                 *lon = x / (double)size * 360.0 - 180;
313         }
314
315         if (lat) {
316                 double real_zoom = log2(size/256.0);
317                 int floored_zoom = floor(real_zoom);
318                 double lat1;
319
320                 if (floored_zoom >= ZOOM_MAX) {
321                         lat1 = map_center[ZOOM_MAX].lat;
322                 } else {
323                         lat1 = map_center[floored_zoom].lat + (map_center[floored_zoom + 1].lat - map_center[floored_zoom].lat) * (real_zoom - floored_zoom);
324                 }
325
326                 double radLat = (lat1 * (2.0 * M_PI)) / 360.0;
327                 double ecc = 0.08181919084262157;
328
329                 double sinPhi = sin(radLat);
330                 double eSinPhi = ecc * sinPhi;
331
332                 double pw = pow((1.0 - eSinPhi) / (1.0 + eSinPhi), ecc);
333                 double retVal = log(((1.0 + sinPhi) / (1.0 - sinPhi)) * pw) / 2.0;
334
335                 double yy = retVal / (2 * M_PI / (double)size);
336
337                 double phiEpsilon = 1E-7;
338                 double phiMaxIter = 12.0;
339
340                 static double E = 2.718281828459045;
341                 double t = pow(E, (-(floor(yy+128-y)) * (2 * M_PI / (double)size)));
342
343                 double prevPhi = mercator_unproject(t);
344                 double newPhi = find_rad_phi(prevPhi, t);
345
346                 double iterCount = 0.0;
347
348                 while ((iterCount < phiMaxIter) && (fabs(prevPhi - newPhi) > phiEpsilon)) {
349                         prevPhi = newPhi;
350                         newPhi = find_rad_phi(prevPhi, t);
351                         iterCount++;
352                 }
353                 *lat = newPhi * 180.0 / M_PI;
354         }
355
356         return EINA_TRUE;
357 }
358
359 static Eina_Bool _module_init(void)
360 {
361         int z;
362         for (z = ZOOM_MIN; z <= ZOOM_MAX; z++){
363                 source_req_done[z] = 0;
364                 map_request(z);
365         }
366
367         return EINA_TRUE;
368 }
369
370 static void _module_shutdown(void)
371 {
372         if (decarta_init) {
373                 decarta_search_map_async_cancel();
374         }
375 }
376
377 EINA_MODULE_INIT(_module_init);
378 EINA_MODULE_SHUTDOWN(_module_shutdown);
379