Add:Core:Support for FRA FRA NLS Setting
[navit-package] / navit / coord.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
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, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <glib.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include "debug.h"
26 #include "item.h"
27 #include "coord.h"
28 #include "transform.h"
29 #include "projection.h"
30 /**
31  * @defgroup coord Coordinate handling functions
32  * @{
33  */
34
35 /**
36  * Get a coordinate
37  *
38  * @param p Pointer to the coordinate
39  * @returns the coordinate
40  */
41
42 struct coord *
43 coord_get(unsigned char **p)
44 {
45         struct coord *ret=(struct coord *)(*p);
46         *p += sizeof(*ret);
47         return ret;
48 }
49
50 struct coord *
51 coord_new(int x, int y)
52 {
53         struct coord *c=g_new(struct coord, 1);
54
55         c->x=x;
56         c->y=y;
57
58         return c;
59 }
60
61 struct coord *
62 coord_new_from_attrs(struct attr *parent, struct attr **attrs)
63 {
64         struct attr *x,*y;
65         x=attr_search(attrs, NULL, attr_x);
66         y=attr_search(attrs, NULL, attr_y);
67         if (!x || !y)
68                 return NULL;
69         return coord_new(x->u.num, y->u.num);
70 }
71
72
73 void
74 coord_destroy(struct coord *c)
75 {
76         g_free(c);
77 }
78
79 struct coord_rect *
80 coord_rect_new(struct coord *lu, struct coord *rl)
81 {
82         struct coord_rect *r=g_new(struct coord_rect, 1);
83
84         dbg_assert(lu->x <= rl->x);
85         dbg_assert(lu->y >= rl->y);
86
87         r->lu=*lu;
88         r->rl=*rl;
89
90         return r;
91         
92 }
93
94 void
95 coord_rect_destroy(struct coord_rect *r)
96 {
97         g_free(r);
98 }
99
100 int 
101 coord_rect_overlap(struct coord_rect *r1, struct coord_rect *r2)
102 {
103         dbg_assert(r1->lu.x <= r1->rl.x);
104         dbg_assert(r1->lu.y >= r1->rl.y);
105         dbg_assert(r2->lu.x <= r2->rl.x);
106         dbg_assert(r2->lu.y >= r2->rl.y);
107         dbg(1,"0x%x,0x%x - 0x%x,0x%x vs 0x%x,0x%x - 0x%x,0x%x\n", r1->lu.x, r1->lu.y, r1->rl.x, r1->rl.y, r2->lu.x, r2->lu.y, r2->rl.x, r2->rl.y);
108         if (r1->lu.x > r2->rl.x)
109                 return 0;
110         if (r1->rl.x < r2->lu.x)
111                 return 0;
112         if (r1->lu.y < r2->rl.y)
113                 return 0;
114         if (r1->rl.y > r2->lu.y)
115                 return 0;
116         return 1;
117 }
118
119 int
120 coord_rect_contains(struct coord_rect *r, struct coord *c)
121 {
122         dbg_assert(r->lu.x <= r->rl.x);
123         dbg_assert(r->lu.y >= r->rl.y);
124         if (c->x < r->lu.x)
125                 return 0;
126         if (c->x > r->rl.x)
127                 return 0;
128         if (c->y < r->rl.y)
129                 return 0;
130         if (c->y > r->lu.y)
131                 return 0;
132         return 1;
133 }
134
135 void
136 coord_rect_extend(struct coord_rect *r, struct coord *c)
137 {
138         if (c->x < r->lu.x)
139                 r->lu.x=c->x;
140         if (c->x > r->rl.x)
141                 r->rl.x=c->x;
142         if (c->y < r->rl.y)
143                 r->rl.y=c->y;
144         if (c->y > r->lu.y)
145                 r->lu.y=c->y;
146 }
147
148 /**
149  * Parses \c char \a *c_str and writes back the coordinates to \c coord \a *c_ret. Uses \c projection \a pro if no projection is given in \c char \a *c_str.
150  * The format for \a *c_str can be: 
151  *      \li [Proj:]-0xX [-]0xX 
152  *          - where Proj can be mg/garmin, defaults to mg
153  *      \li [Proj:][D][D]Dmm.ss[S][S] N/S [D][D]DMM.ss[S][S]... E/W
154  *      \li [Proj:][-][D]D.d[d]... [-][D][D]D.d[d]
155  *          - where Proj can be geo
156  *
157  * @param *c_str String to be parsed
158  * @param pro Projection of the string
159  * @param *pc_ret Where the \a pcoord should get stored
160  * @returns The lenght of the parsed string
161  */
162
163 int
164 coord_parse(const char *c_str, enum projection pro, struct coord *c_ret)
165 {
166         int debug=0;
167         char *proj=NULL,*s,*co;
168         const char *str=c_str;
169         int args,ret = 0;
170         struct coord_geo g;
171         struct coord c;
172         enum projection str_pro=projection_none;
173
174         dbg(1,"enter('%s',%d,%p)\n", c_str, pro, c_ret);
175         s=strchr(str,' ');
176         co=strchr(str,':');
177         if (co && co < s) {
178                 proj=malloc(co-str+1);
179                 strncpy(proj, str, co-str);
180                 proj[co-str]='\0';
181                 dbg(1,"projection=%s\n", proj);
182                 str=co+1;
183                 s=strchr(str,' ');
184                 if (!strcmp(proj, "mg"))
185                         str_pro = projection_mg;
186                 else if (!strcmp(proj, "garmin"))
187                         str_pro = projection_garmin;
188                 else if (!strcmp(proj, "geo"))
189                         str_pro = projection_none;
190                 else {
191                         dbg(0, "Unknown projection: %s\n", proj);
192                         goto out;
193                 }
194         }
195         if (! s) {
196                 ret=0;
197                 goto out;
198         }
199         while (*s == ' ') {
200                 s++;
201         }
202         if (!strncmp(s, "0x", 2) || !strncmp(s, "-0x", 3)) {
203                 args=sscanf(str, "%i %i%n",&c.x, &c.y, &ret);
204                 if (args < 2)
205                         goto out;
206                 dbg(1,"str='%s' x=0x%x y=0x%x c=%d\n", str, c.x, c.y, ret);
207                 dbg(1,"rest='%s'\n", str+ret);
208
209                 if (str_pro == projection_none) 
210                         str_pro=projection_mg;
211                 if (str_pro != pro) {
212                         transform_to_geo(str_pro, &c, &g);
213                         transform_from_geo(pro, &g, &c);
214                 }
215                 *c_ret=c;
216         } else if (*s == 'N' || *s == 'n' || *s == 'S' || *s == 's') {
217                 double lng, lat;
218                 char ns, ew;
219                 dbg(1,"str='%s'\n", str);
220                 args=sscanf(str, "%lf %c %lf %c%n", &lat, &ns, &lng, &ew, &ret);
221                 dbg(1,"args=%d\n", args);
222                 dbg(1,"lat=%f %c lon=%f %c\n", lat, ns, lng, ew);
223                 if (args < 4)
224                         goto out;
225                 dbg(1,"projection=%d str_pro=%d projection_none=%d\n", pro, str_pro, projection_none);
226                 if (str_pro == projection_none) {
227                         g.lat=floor(lat/100);
228                         lat-=g.lat*100;
229                         g.lat+=lat/60;
230                         g.lng=floor(lng/100);
231                         lng-=g.lng*100;
232                         g.lng+=lng/60;
233                         if (ns == 's' || ns == 'S')
234                                 g.lat=-g.lat;
235                         if (ew == 'w' || ew == 'W')
236                                 g.lng=-g.lng;
237                         dbg(1,"transform_from_geo(%f,%f)",g.lat,g.lng);
238                         transform_from_geo(pro, &g, c_ret);
239                         dbg(1,"result 0x%x,0x%x\n", c_ret->x,c_ret->y);
240                 }
241                 dbg(3,"str='%s' x=%f ns=%c y=%f ew=%c c=%d\n", str, lng, ns, lat, ew, ret);
242                 dbg(3,"rest='%s'\n", str+ret);
243         } else {
244                 double lng, lat;
245                 args=sscanf(str, "%lf %lf%n", &lng, &lat, &ret);
246                 if (args < 2)
247                         goto out;
248                 dbg(1,"str='%s' x=%f y=%f  c=%d\n", str, lng, lat, ret);
249                 dbg(1,"rest='%s'\n", str+ret);
250                 g.lng=lng;
251                 g.lat=lat;
252                 transform_from_geo(pro, &g, c_ret);
253         }
254         if (debug)
255                 printf("rest='%s'\n", str+ret);
256         ret+=str-c_str;
257         if (debug) {
258                 printf("args=%d\n", args);
259                 printf("ret=%d delta=%d ret_str='%s'\n", ret, GPOINTER_TO_INT(str-c_str), c_str+ret);
260         }
261 out:
262         if (proj)
263                 free(proj);
264         return ret;
265 }
266
267 /**
268  * A wrapper for pcoord_parse that also return the projection
269  * @param *c_str String to be parsed
270  * @param pro Projection of the string
271  * @param *pc_ret Where the \a pcoord should get stored
272  * @returns The lenght of the parsed string
273  */
274
275 int
276 pcoord_parse(const char *c_str, enum projection pro, struct pcoord *pc_ret)
277 {
278     struct coord c;
279     int ret;
280     ret = coord_parse(c_str, pro, &c);
281     pc_ret->x = c.x;
282     pc_ret->y = c.y;
283     pc_ret->pro = pro;
284     return ret;
285 }
286
287 void
288 coord_print(enum projection pro, struct coord *c, FILE *out) {
289         unsigned int x;
290         unsigned int y;
291         char *sign_x = "";
292         char *sign_y = "";
293         
294         if ( c->x < 0 ) {
295                 x = -c->x;
296                 sign_x = "-";
297         } else {
298                 x = c->x;
299         }
300         if ( c->y < 0 ) {
301                 y = -c->y;
302                 sign_y = "-";
303         } else {
304                 y = c->y;
305         }
306         fprintf( out, "%s: %s0x%x %s0x%x\n",
307                  projection_to_name( pro , NULL),
308                  sign_x, x,
309                  sign_y, y );
310         return;
311 }
312
313 /**
314  * @brief Converts a lat/lon into a text formatted text string.
315  * @param lat The latitude
316  * @param lng The longitude
317  * @param fmt The format to use. 
318  *    @li DEGREES=>(45.5000N 100.9000S)
319  *    @li DEGREES_MINUTES=>(45 30.))00N 100 120.54.0000S)
320  *    @li DEGREES_MINUTES_SECONDS=>(4530.0000N 12054.0000S)
321  *           
322  * 
323  * @param buffer  A buffer large enough to hold the output + a terminating NULL (26 bytes)
324  * @param size The size of the buffer
325  *
326  */
327 void coord_format(float lat,float lng, enum coord_format fmt, char * buffer, int size)
328 {
329
330         char lat_c='N';
331         char lng_c='E';
332         float lat_deg,lat_min,lat_sec;
333         float lng_deg,lng_min,lng_sec;
334
335         if (lng < 0) {
336                 lng=-lng;
337                 lng_c='W';
338         }
339         if (lat < 0) {
340                 lat=-lat;
341                 lat_c='S';
342         }
343         lat_deg=lat;
344         lat_min=(lat-floor(lat_deg))*60;
345         lat_sec=fmod(lat*3600,60);
346         lng_deg=lng;
347         lng_min=(lng-floor(lng_deg))*60;
348         lng_sec=fmod(lng*3600,60);
349         switch(fmt)
350         {
351
352         case DEGREES_DECIMAL:
353           snprintf(buffer,size,"%02.6f%c %03.7f%c",lat,lat_c,lng,lng_c);
354           break;
355         case DEGREES_MINUTES:
356           snprintf(buffer,size,"%02.0f %07.4f%c %03.0f %07.4f%c",floor(lat_deg),lat_min , lat_c, floor(lng), lng_min, lng_c);
357                    break;
358         case DEGREES_MINUTES_SECONDS:
359           snprintf(buffer,size,"%02.0f%07.4f%c %03.0f%07.4f%c",floor(lat), fmod(lat*60,60), lat_c, floor(lng), fmod(lng*60,60), lng_c);
360           break;
361           
362         
363         }
364         
365 }
366
367 unsigned int 
368 coord_hash(const void *key)
369 {
370         const struct coord *c=key;
371         return c->x^c->y;
372 }
373
374 int
375 coord_equal(const void *a, const void *b)
376 {
377         const struct coord *c_a=a;
378         const struct coord *c_b=b;
379         if (c_a->x == c_b->x && c_a->y == c_b->y)
380                 return TRUE;
381         return FALSE;
382 }
383 /** @} */