Fix:Core:Fixed transformation with ENABLE_ROLL off
[navit-package] / navit / transform.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 <assert.h>
21 #include <stdio.h>
22 #include <math.h>
23 #include <limits.h>
24 #include <glib.h>
25 #include <string.h>
26 #include "config.h"
27 #include "coord.h"
28 #include "debug.h"
29 #include "item.h"
30 #include "map.h"
31 #include "transform.h"
32 #include "projection.h"
33 #include "point.h"
34
35 #define POST_SHIFT 8
36 /* #define ENABLE_ROLL */
37
38 struct transformation {
39         int yaw;                /* Rotation angle */
40         int pitch;
41         int ddd;
42         int m00,m01,m10,m11;    /* 2d transformation matrix */
43         int xyscale;
44         int m20,m21;            /* additional 3d parameters */
45 #ifdef ENABLE_ROLL
46         int roll;
47         int m02,m12,m22; 
48         int hog;
49         double im02,im12,im20,im21,im22;
50 #endif
51         double im00,im01,im10,im11;     /* inverse 2d transformation matrix */
52         struct map_selection *map_sel;
53         struct map_selection *screen_sel;
54         struct point screen_center;
55         int screen_dist;
56         int offx,offy,offz;
57         struct coord map_center;        /* Center of source rectangle */
58         enum projection pro;
59         double scale;           /* Scale factor */
60         int scale_shift;
61         int order;
62 };
63
64 static void
65 transform_setup_matrix(struct transformation *t)
66 {
67         double det;
68         double fac;
69         double yawc=cos(M_PI*t->yaw/180);
70         double yaws=sin(M_PI*t->yaw/180);
71         double pitchc=cos(-M_PI*t->pitch/180);
72         double pitchs=sin(-M_PI*t->pitch/180);
73 #ifdef ENABLE_ROLL      
74         double rollc=cos(M_PI*t->roll/180);
75         double rolls=sin(M_PI*t->roll/180);
76 #endif
77
78         int scale=t->scale;
79         int order_dir=-1;
80
81         dbg(1,"yaw=%d pitch=%d center=0x%x,0x%x\n", t->yaw, t->pitch, t->map_center.x, t->map_center.y);
82         t->scale_shift=0;
83         t->order=14;
84         if (t->scale >= 1) {
85                 scale=t->scale;
86         } else {
87                 scale=1.0/t->scale;
88                 order_dir=1;
89         }
90         while (scale > 1) {
91                 if (order_dir < 0)
92                         t->scale_shift++;
93                 t->order+=order_dir;
94                 scale >>= 1;
95         }
96         fac=(1 << POST_SHIFT) * (1 << t->scale_shift) / t->scale;
97         dbg(1,"scale_shift=%d order=%d scale=%f fac=%f\n", t->scale_shift, t->order,t->scale,fac);
98         
99 #ifdef ENABLE_ROLL
100         t->m00=rollc*yawc*fac;
101         t->m01=rollc*yaws*fac;
102         t->m02=-rolls*fac;
103         t->m10=(pitchs*rolls*yawc-pitchc*yaws)*(-fac);
104         t->m11=(pitchs*rolls*yaws+pitchc*yawc)*(-fac);
105         t->m12=pitchs*rollc*(-fac);
106         t->m20=(pitchc*rolls*yawc+pitchs*yaws)*fac;
107         t->m21=(pitchc*rolls*yaws-pitchs*yawc)*fac;
108         t->m22=pitchc*rollc*fac;
109 #else
110         t->m00=yawc*fac;
111         t->m01=yaws*fac;
112         t->m10=(-pitchc*yaws)*(-fac);
113         t->m11=pitchc*yawc*(-fac);
114         t->m20=pitchs*yaws*fac;
115         t->m21=(-pitchs*yawc)*fac;
116 #endif
117         t->offz=0;
118         t->xyscale=1;
119         t->ddd=0;
120         t->offx=t->screen_center.x;
121         t->offy=t->screen_center.y;
122         if (t->pitch) {
123                 t->ddd=1;
124                 t->offz=t->screen_dist;
125                 t->xyscale=t->offz;
126         }
127 #ifdef ENABLE_ROLL
128         det=(double)t->m00*(double)t->m11*(double)t->m22+
129             (double)t->m01*(double)t->m12*(double)t->m20+
130             (double)t->m02*(double)t->m10*(double)t->m21-
131             (double)t->m02*(double)t->m11*(double)t->m20-
132             (double)t->m01*(double)t->m10*(double)t->m22-
133             (double)t->m00*(double)t->m12*(double)t->m21;
134
135         t->im00=(t->m11*t->m22-t->m12*t->m21)/det;
136         t->im01=(t->m02*t->m21-t->m01*t->m22)/det;
137         t->im02=(t->m01*t->m12-t->m02*t->m11)/det;
138         t->im10=(t->m12*t->m20-t->m10*t->m22)/det;
139         t->im11=(t->m00*t->m22-t->m02*t->m20)/det;
140         t->im12=(t->m02*t->m10-t->m00*t->m12)/det;
141         t->im20=(t->m10*t->m21-t->m11*t->m20)/det;
142         t->im21=(t->m01*t->m20-t->m00*t->m21)/det;
143         t->im22=(t->m00*t->m11-t->m01*t->m10)/det;
144 #else
145         det=((double)t->m00*(double)t->m11-(double)t->m01*(double)t->m10);
146         t->im00=t->m11/det;
147         t->im01=-t->m01/det;
148         t->im10=-t->m10/det;
149         t->im11=t->m00/det;
150 #endif
151 }
152
153 struct transformation *
154 transform_new(void)
155 {
156         struct transformation *this_;
157
158         this_=g_new0(struct transformation, 1);
159         this_->screen_dist=100;
160 #if 0
161         this_->pitch=20;
162 #endif
163 #if 0
164         this_->roll=30;
165         this_->hog=1000;
166 #endif
167         transform_setup_matrix(this_);
168         return this_;
169 }
170
171 struct transformation *
172 transform_dup(struct transformation *t)
173 {
174         struct transformation *ret=g_new0(struct transformation, 1);
175         *ret=*t;
176         return ret;
177 }
178
179 static const double gar2geo_units = 360.0/(1<<24);
180 static const double geo2gar_units = 1/(360.0/(1<<24));
181
182 void
183 transform_to_geo(enum projection pro, struct coord *c, struct coord_geo *g)
184 {
185         switch (pro) {
186         case projection_mg:
187                 g->lng=c->x/6371000.0/M_PI*180;
188                 g->lat=atan(exp(c->y/6371000.0))/M_PI*360-90;
189                 break;
190         case projection_garmin:
191                 g->lng=c->x*gar2geo_units;
192                 g->lat=c->y*gar2geo_units;
193                 break;
194         default:
195                 break;
196         }
197 }
198
199 void
200 transform_from_geo(enum projection pro, struct coord_geo *g, struct coord *c)
201 {
202         switch (pro) {
203         case projection_mg:
204                 c->x=g->lng*6371000.0*M_PI/180;
205                 c->y=log(tan(M_PI_4+g->lat*M_PI/360))*6371000.0;
206                 break;
207         case projection_garmin:
208                 c->x=g->lng*geo2gar_units;
209                 c->y=g->lat*geo2gar_units;
210                 break;
211         default:
212                 break;
213         }
214 }
215
216 void
217 transform_from_to(struct coord *cfrom, enum projection from, struct coord *cto, enum projection to)
218 {
219         struct coord_geo g;
220         transform_to_geo(from, cfrom, &g);
221         transform_from_geo(to, &g, cto);
222 }
223
224 void
225 transform_geo_to_cart(struct coord_geo *geo, double a, double b, struct coord_geo_cart *cart)
226 {
227         double n,ee=1-b*b/(a*a);
228         n = a/sqrt(1-ee*sin(geo->lat)*sin(geo->lat));
229         cart->x=n*cos(geo->lat)*cos(geo->lng);
230         cart->y=n*cos(geo->lat)*sin(geo->lng);
231         cart->z=n*(1-ee)*sin(geo->lat);
232 }
233
234 void
235 transform_cart_to_geo(struct coord_geo_cart *cart, double a, double b, struct coord_geo *geo)
236 {
237         double lat,lati,n,ee=1-b*b/(a*a), lng = atan(cart->y/cart->x);
238
239         lat = atan(cart->z / sqrt((cart->x * cart->x) + (cart->y * cart->y)));
240         do
241         {
242                 lati = lat;
243
244                 n = a / sqrt(1-ee*sin(lat)*sin(lat));
245                 lat = atan((cart->z + ee * n * sin(lat)) / sqrt(cart->x * cart->x + cart->y * cart->y));
246         }
247         while (fabs(lat - lati) >= 0.000000000000001);
248
249         geo->lng=lng/M_PI*180;
250         geo->lat=lat/M_PI*180;
251 }
252
253
254 void
255 transform_datum(struct coord_geo *from, enum map_datum from_datum, struct coord_geo *to, enum map_datum to_datum)
256 {
257 }
258
259 int
260 transform(struct transformation *t, enum projection pro, struct coord *c, struct point *p, int count, int unique, int width, int *width_return)
261 {
262         struct coord c1;
263         int xcn, ycn; 
264         struct coord_geo g;
265         int xc, yc, zc=0, xco=0, yco=0, zco=0;
266         int xm,ym,zct;
267         int zlimit=1000;
268         int visible, visibleo=-1;
269         int i,j = 0;
270         dbg(1,"count=%d\n", count);
271         for (i=0; i < count; i++) {
272                 if (pro == t->pro) {
273                         xc=c[i].x;
274                         yc=c[i].y;
275                 } else {
276                         transform_to_geo(pro, &c[i], &g);
277                         transform_from_geo(t->pro, &g, &c1);
278                         xc=c1.x;
279                         yc=c1.y;
280                 }
281                 xm=xc;
282                 ym=yc;
283 //              dbg(2,"0x%x, 0x%x - 0x%x,0x%x contains 0x%x,0x%x\n", t->r.lu.x, t->r.lu.y, t->r.rl.x, t->r.rl.y, c->x, c->y);
284 //              ret=coord_rect_contains(&t->r, c);
285                 xc-=t->map_center.x;
286                 yc-=t->map_center.y;
287                 xc >>= t->scale_shift;
288                 yc >>= t->scale_shift;
289 #ifdef ENABLE_ROLL              
290                 xcn=xc*t->m00+yc*t->m01+t->hog*t->m02;
291                 ycn=xc*t->m10+yc*t->m11+t->hog*t->m12;
292 #else
293                 xcn=xc*t->m00+yc*t->m01;
294                 ycn=xc*t->m10+yc*t->m11;
295 #endif
296
297                 if (t->ddd) {
298 #ifdef ENABLE_ROLL              
299                         zc=(xc*t->m20+yc*t->m21+t->hog*t->m22);
300 #else
301                         zc=(xc*t->m20+yc*t->m21);
302 #endif
303                         zct=zc;
304                         zc+=t->offz << POST_SHIFT;
305                         dbg(1,"zc=%d\n", zc);
306                         dbg(1,"zc(%d)=xc(%d)*m20(%d)+yc(%d)*m21(%d)\n", (xc*t->m20+yc*t->m21), xc, t->m20, yc, t->m21);
307                         /* visibility */
308                         visible=(zc < zlimit ? 0:1);
309                         dbg(1,"visible=%d old %d\n", visible, visibleo);
310                         if (visible != visibleo && visibleo != -1) { 
311                                 dbg(1,"clipping (%d,%d,%d)-(%d,%d,%d) (%d,%d,%d)\n", xcn, ycn, zc, xco, yco, zco, xco-xcn, yco-ycn, zco-zc);
312                                 if (zco != zc) {
313                                         xcn=xcn+(long long)(xco-xcn)*(zlimit-zc)/(zco-zc);
314                                         ycn=ycn+(long long)(yco-ycn)*(zlimit-zc)/(zco-zc);
315                                 }
316                                 dbg(1,"result (%d,%d,%d) * %d / %d\n", xcn,ycn,zc,zlimit-zc,zco-zc);
317                                 zc=zlimit;
318                                 xco=xcn;
319                                 yco=ycn;
320                                 zco=zc;
321                                 if (visible)
322                                         i--;
323                                 visibleo=visible;
324                         } else {
325                                 xco=xcn;
326                                 yco=ycn;
327                                 zco=zc;
328                                 visibleo=visible;
329                                 if (! visible)
330                                         continue;
331                         }
332                         dbg(1,"zc=%d\n", zc);
333                         dbg(1,"xcn %d ycn %d\n", xcn, ycn);
334                         dbg(1,"%d,%d %d\n",xc,yc,zc);
335 #if 0
336                         dbg(0,"%d/%d=%d %d/%d=%d\n",xcn,xc,xcn/xc,ycn,yc,ycn/yc);
337 #endif
338 #if 1
339                         xc=(long long)xcn*t->xyscale/zc;
340                         yc=(long long)ycn*t->xyscale/zc;
341 #else
342                         xc=xcn/(1000+zc);
343                         yc=ycn/(1000+zc);
344 #endif
345                         dbg(1,"%d,%d %d\n",xc,yc,zc);
346                 } else {
347                         xc=xcn;
348                         yc=ycn;
349                         xc>>=POST_SHIFT;
350                         yc>>=POST_SHIFT;
351                 }
352                 xc+=t->offx;
353                 yc+=t->offy;
354                 dbg(1,"xc=%d yc=%d\n", xc, yc);
355                 if (j == 0 || !unique || p[j-1].x != xc || p[j-1].y != yc) {
356                         p[j].x=xc;
357                         p[j].y=yc;
358                         if (width_return) {
359                                 if (t->ddd) 
360                                         width_return[j]=width*(t->offz << POST_SHIFT)/zc;
361                                 else 
362                                         width_return[j]=width;
363                         }
364                         j++;
365                 }
366         }
367         return j;
368 }
369
370 void
371 transform_reverse(struct transformation *t, struct point *p, struct coord *c)
372 {
373         double zc,xc,yc,xcn,ycn,q;
374         double offz=t->offz << POST_SHIFT;
375         xc=p->x - t->offx;
376         yc=p->y - t->offy;
377         if (t->ddd) {
378                 xc/=t->xyscale;
379                 yc/=t->xyscale;
380                 double f00=xc*t->im00*t->m20;
381                 double f01=yc*t->im01*t->m20;
382                 double f10=xc*t->im10*t->m21;
383                 double f11=yc*t->im11*t->m21;
384 #ifdef ENABLE_ROLL      
385                 q=(1-f00-f01-t->im02*t->m20-f10-f11-t->im12*t->m21);
386                 if (q < 0) 
387                         q=0.15;
388                 zc=(offz*((f00+f01+f10+f11))+t->hog*t->m22)/q;
389 #else
390                 q=(1-f00-f01-f10-f11);
391                 if (q < 0) 
392                         q=0.15;
393                 zc=offz*(f00+f01+f10+f11)/q;
394 #endif
395                 xcn=xc*(zc+offz);
396                 ycn=yc*(zc+offz);
397 #ifdef ENABLE_ROLL      
398                 xc=xcn*t->im00+ycn*t->im01+zc*t->im02;
399                 yc=xcn*t->im10+ycn*t->im11+zc*t->im12;
400 #else
401                 xc=xcn*t->im00+ycn*t->im01;
402                 yc=xcn*t->im10+ycn*t->im11;
403 #endif
404
405         } else {
406                 xcn=xc;
407                 ycn=yc;
408                 xc=(xcn*t->im00+ycn*t->im01)*(1 << POST_SHIFT);
409                 yc=(xcn*t->im10+ycn*t->im11)*(1 << POST_SHIFT);
410         }
411         c->x=xc*(1 << t->scale_shift)+t->map_center.x;
412         c->y=yc*(1 << t->scale_shift)+t->map_center.y;
413 }
414
415 enum projection
416 transform_get_projection(struct transformation *this_)
417 {
418         return this_->pro;
419 }
420
421 void
422 transform_set_projection(struct transformation *this_, enum projection pro)
423 {
424         this_->pro=pro;
425 }
426
427 static int
428 min4(int v1,int v2, int v3, int v4)
429 {
430         int res=v1;
431         if (v2 < res)
432                 res=v2;
433         if (v3 < res)
434                 res=v3;
435         if (v4 < res)
436                 res=v4;
437         return res;
438 }
439
440 static int
441 max4(int v1,int v2, int v3, int v4)
442 {
443         int res=v1;
444         if (v2 > res)
445                 res=v2;
446         if (v3 > res)
447                 res=v3;
448         if (v4 > res)
449                 res=v4;
450         return res;
451 }
452
453 struct map_selection *
454 transform_get_selection(struct transformation *this_, enum projection pro, int order)
455 {
456
457         struct map_selection *ret,*curri,*curro;
458         struct coord_geo g;
459         
460         ret=map_selection_dup(this_->map_sel);
461         curri=this_->map_sel;
462         curro=ret;
463         while (curri) {
464                 if (this_->pro != pro) {
465                         transform_to_geo(this_->pro, &curri->u.c_rect.lu, &g);
466                         transform_from_geo(pro, &g, &curro->u.c_rect.lu);
467                         dbg(1,"%f,%f", g.lat, g.lng);
468                         transform_to_geo(this_->pro, &curri->u.c_rect.rl, &g);
469                         transform_from_geo(pro, &g, &curro->u.c_rect.rl);
470                         dbg(1,": - %f,%f\n", g.lat, g.lng);
471                 }
472                 dbg(1,"transform rect for %d is %d,%d - %d,%d\n", pro, curro->u.c_rect.lu.x, curro->u.c_rect.lu.y, curro->u.c_rect.rl.x, curro->u.c_rect.rl.y);
473                 curro->order+=order;
474                 curro->range=item_range_all;
475                 curri=curri->next;
476                 curro=curro->next;
477         }
478         return ret;
479 }
480
481 struct coord *
482 transform_center(struct transformation *this_)
483 {
484         return &this_->map_center;
485 }
486
487 struct coord *
488 transform_get_center(struct transformation *this_)
489 {
490         return &this_->map_center;
491 }
492
493 void
494 transform_set_center(struct transformation *this_, struct coord *c)
495 {
496         this_->map_center=*c;
497 }
498
499
500 void
501 transform_set_yaw(struct transformation *t,int yaw)
502 {
503         t->yaw=yaw;
504         transform_setup_matrix(t);
505 }
506
507 int
508 transform_get_yaw(struct transformation *this_)
509 {
510         return this_->yaw;
511 }
512
513 void
514 transform_set_pitch(struct transformation *this_,int pitch)
515 {
516         this_->pitch=pitch;
517         transform_setup_matrix(this_);
518 }
519 int
520 transform_get_pitch(struct transformation *this_)
521 {
522         return this_->pitch;
523 }
524
525 #ifdef ENABLE_ROLL
526 void
527 transform_set_roll(struct transformation *this_,int roll)
528 {
529         this_->roll=roll;
530         transform_setup_matrix(this_);
531 }
532
533 int
534 transform_get_roll(struct transformation *this_)
535 {
536         return this_->roll;
537 }
538 #endif
539
540 void
541 transform_set_distance(struct transformation *this_,int distance)
542 {
543         this_->screen_dist=distance;
544         transform_setup_matrix(this_);
545 }
546
547 int
548 transform_get_distance(struct transformation *this_)
549 {
550         return this_->screen_dist;
551 }
552
553 void
554 transform_set_screen_selection(struct transformation *t, struct map_selection *sel)
555 {
556         map_selection_destroy(t->screen_sel);
557         t->screen_sel=map_selection_dup(sel);
558         if (sel) {
559                 t->screen_center.x=(sel->u.p_rect.rl.x-sel->u.p_rect.lu.x)/2;
560                 t->screen_center.y=(sel->u.p_rect.rl.y-sel->u.p_rect.lu.y)/2;
561                 transform_setup_matrix(t);
562         }
563 }
564
565 void
566 transform_set_screen_center(struct transformation *t, struct point *p)
567 {
568         t->screen_center=*p;
569 }
570
571 #if 0
572 void
573 transform_set_size(struct transformation *t, int width, int height)
574 {
575         t->width=width;
576         t->height=height;
577 }
578 #endif
579
580 void
581 transform_get_size(struct transformation *t, int *width, int *height)
582 {
583         struct point_rect *r;
584         if (t->screen_sel) {
585                 r=&t->screen_sel->u.p_rect;
586                 *width=r->rl.x-r->lu.x;
587                 *height=r->rl.y-r->lu.y;
588         }
589 }
590
591 void
592 transform_setup(struct transformation *t, struct pcoord *c, int scale, int yaw)
593 {
594         t->pro=c->pro;
595         t->map_center.x=c->x;
596         t->map_center.y=c->y;
597         t->scale=scale/16.0;
598         transform_set_yaw(t, yaw);
599 }
600
601 #if 0
602
603 void
604 transform_setup_source_rect_limit(struct transformation *t, struct coord *center, int limit)
605 {
606         t->center=*center;
607         t->scale=1;
608         t->angle=0;
609         t->r.lu.x=center->x-limit;
610         t->r.rl.x=center->x+limit;
611         t->r.rl.y=center->y-limit;
612         t->r.lu.y=center->y+limit;
613 }
614 #endif
615
616 void
617 transform_setup_source_rect(struct transformation *t)
618 {
619         int i;
620         struct coord screen[4];
621         struct point screen_pnt[4];
622         struct point_rect *pr;
623         struct map_selection *ms,*msm,*next,**msm_last;
624         ms=t->map_sel;
625         while (ms) {
626                 next=ms->next;
627                 g_free(ms);
628                 ms=next;
629         }
630         t->map_sel=NULL;
631         msm_last=&t->map_sel;
632         ms=t->screen_sel;
633         while (ms) {
634                 msm=g_new0(struct map_selection, 1);
635                 *msm=*ms;
636                 pr=&ms->u.p_rect;
637                 screen_pnt[0].x=pr->lu.x;
638                 screen_pnt[0].y=pr->lu.y;
639                 screen_pnt[1].x=pr->rl.x;
640                 screen_pnt[1].y=pr->lu.y;
641                 screen_pnt[2].x=pr->lu.x;
642                 screen_pnt[2].y=pr->rl.y;
643                 screen_pnt[3].x=pr->rl.x;
644                 screen_pnt[3].y=pr->rl.y;
645                 for (i = 0 ; i < 4 ; i++) {
646                         transform_reverse(t, &screen_pnt[i], &screen[i]);
647                         dbg(1,"map(%d) %d,%d=0x%x,0x%x\n", i,screen_pnt[i].x, screen_pnt[i].y, screen[i].x, screen[i].y);
648                 }
649                 msm->u.c_rect.lu.x=min4(screen[0].x,screen[1].x,screen[2].x,screen[3].x);
650                 msm->u.c_rect.rl.x=max4(screen[0].x,screen[1].x,screen[2].x,screen[3].x);
651                 msm->u.c_rect.rl.y=min4(screen[0].y,screen[1].y,screen[2].y,screen[3].y);
652                 msm->u.c_rect.lu.y=max4(screen[0].y,screen[1].y,screen[2].y,screen[3].y);
653                 dbg(1,"%dx%d\n", msm->u.c_rect.rl.x-msm->u.c_rect.lu.x,
654                                  msm->u.c_rect.lu.y-msm->u.c_rect.rl.y);
655                 *msm_last=msm;
656                 msm_last=&msm->next;
657                 ms=ms->next;
658         }
659 }
660
661 long
662 transform_get_scale(struct transformation *t)
663 {
664         return (int)(t->scale*16);
665 }
666
667 void
668 transform_set_scale(struct transformation *t, long scale)
669 {
670         t->scale=scale/16.0;
671         transform_setup_matrix(t);
672 }
673
674
675 int
676 transform_get_order(struct transformation *t)
677 {
678         return t->order;
679 }
680
681
682
683 #define TWOPI (M_PI*2)
684 #define GC2RAD(c) ((c) * TWOPI/(1<<24))
685 #define minf(a,b) ((a) < (b) ? (a) : (b))
686
687 static double
688 transform_distance_garmin(struct coord *c1, struct coord *c2)
689 {
690 #ifdef USE_HALVESINE
691         static const int earth_radius = 6371*1000; //m change accordingly
692 // static const int earth_radius  = 3960; //miles
693  
694 //Point 1 cords
695         float lat1  = GC2RAD(c1->y);
696         float long1 = GC2RAD(c1->x);
697
698 //Point 2 cords
699         float lat2  = GC2RAD(c2->y);
700         float long2 = GC2RAD(c2->x);
701
702 //Haversine Formula
703         float dlong = long2-long1;
704         float dlat  = lat2-lat1;
705
706         float sinlat  = sinf(dlat/2);
707         float sinlong = sinf(dlong/2);
708  
709         float a=(sinlat*sinlat)+cosf(lat1)*cosf(lat2)*(sinlong*sinlong);
710         float c=2*asinf(minf(1,sqrt(a)));
711 #ifdef AVOID_FLOAT
712         return round(earth_radius*c);
713 #else
714         return earth_radius*c;
715 #endif
716 #else
717 #define GMETER 2.3887499999999999
718         double dx,dy;
719         dx=c1->x-c2->x;
720         dy=c1->y-c2->y;
721         return sqrt(dx*dx+dy*dy)*GMETER;
722 #undef GMETER
723 #endif
724 }
725
726 double
727 transform_scale(int y)
728 {
729         struct coord c;
730         struct coord_geo g;
731         c.x=0;
732         c.y=y;
733         transform_to_geo(projection_mg, &c, &g);
734         return 1/cos(g.lat/180*M_PI);
735 }
736
737 #ifdef AVOID_FLOAT
738 static int
739 tab_sqrt[]={14142,13379,12806,12364,12018,11741,11517,11333,11180,11051,10943,10850,10770,10701,10640,10587,10540,10499,10462,10429,10400,10373,10349,10327,10307,10289,10273,10257,10243,10231,10219,10208};
740 #endif
741
742 double
743 transform_distance(enum projection pro, struct coord *c1, struct coord *c2)
744 {
745         if (pro == projection_mg) {
746 #ifndef AVOID_FLOAT 
747         double dx,dy,scale=transform_scale((c1->y+c2->y)/2);
748         dx=c1->x-c2->x;
749         dy=c1->y-c2->y;
750         return sqrt(dx*dx+dy*dy)/scale;
751 #else
752         int dx,dy,f,scale=15539;
753         dx=c1->x-c2->x;
754         dy=c1->y-c2->y;
755         if (dx < 0)
756                 dx=-dx;
757         if (dy < 0)
758                 dy=-dy;
759         while (dx > 20000 || dy > 20000) {
760                 dx/=10;
761                 dy/=10;
762                 scale/=10;
763         }
764         if (! dy)
765                 return dx*10000/scale;
766         if (! dx)
767                 return dy*10000/scale;
768         if (dx > dy) {
769                 f=dx*8/dy-8;
770                 if (f >= 32)
771                         return dx*10000/scale;
772                 return dx*tab_sqrt[f]/scale;
773         } else {
774                 f=dy*8/dx-8;
775                 if (f >= 32)
776                         return dy*10000/scale;
777                 return dy*tab_sqrt[f]/scale;
778         }
779 #endif
780         } else if (pro == projection_garmin) {
781                 return transform_distance_garmin(c1, c2);
782         } else {
783                 dbg(0,"Unknown projection: %d\n", pro);
784                 return 0;
785         }
786 }
787
788 double
789 transform_polyline_length(enum projection pro, struct coord *c, int count)
790 {
791         double ret=0;
792         int i;
793
794         for (i = 0 ; i < count-1 ; i++) 
795                 ret+=transform_distance(pro, &c[i], &c[i+1]);
796         return ret;
797 }
798
799 int
800 transform_distance_sq(struct coord *c1, struct coord *c2)
801 {
802         int dx=c1->x-c2->x;
803         int dy=c1->y-c2->y;
804
805         if (dx > 32767 || dy > 32767 || dx < -32767 || dy < -32767)
806                 return INT_MAX;
807         else
808                 return dx*dx+dy*dy;
809 }
810
811 int
812 transform_distance_sq_pc(struct pcoord *c1, struct pcoord *c2)
813 {
814         struct coord p1,p2;
815         p1.x = c1->x; p1.y = c1->y;
816         p2.x = c2->x; p2.y = c2->y;
817         return transform_distance_sq(&p1, &p2);
818 }
819
820 int
821 transform_distance_line_sq(struct coord *l0, struct coord *l1, struct coord *ref, struct coord *lpnt)
822 {
823         int vx,vy,wx,wy;
824         int c1,c2;
825         int climit=1000000;
826         struct coord l;
827
828         vx=l1->x-l0->x;
829         vy=l1->y-l0->y;
830         wx=ref->x-l0->x;
831         wy=ref->y-l0->y;
832
833         c1=vx*wx+vy*wy;
834         if ( c1 <= 0 ) {
835                 if (lpnt)
836                         *lpnt=*l0;
837                 return transform_distance_sq(l0, ref);
838         }
839         c2=vx*vx+vy*vy;
840         if ( c2 <= c1 ) {
841                 if (lpnt)
842                         *lpnt=*l1;
843                 return transform_distance_sq(l1, ref);
844         }
845         while (c1 > climit || c2 > climit) {
846                 c1/=256;
847                 c2/=256;
848         }
849         l.x=l0->x+vx*c1/c2;
850         l.y=l0->y+vy*c1/c2;
851         if (lpnt)
852                 *lpnt=l;
853         return transform_distance_sq(&l, ref);
854 }
855
856 int
857 transform_distance_polyline_sq(struct coord *c, int count, struct coord *ref, struct coord *lpnt, int *pos)
858 {
859         int i,dist,distn;
860         struct coord lp;
861         if (count < 2)
862                 return INT_MAX;
863         if (pos)
864                 *pos=0;
865         dist=transform_distance_line_sq(&c[0], &c[1], ref, lpnt);
866         for (i=2 ; i < count ; i++) {
867                 distn=transform_distance_line_sq(&c[i-1], &c[i], ref, &lp);
868                 if (distn < dist) {
869                         dist=distn;
870                         if (lpnt)
871                                 *lpnt=lp;
872                         if (pos)
873                                 *pos=i-1;
874                 }
875         }
876         return dist;
877 }
878
879
880 void
881 transform_print_deg(double deg)
882 {
883         printf("%2.0f:%2.0f:%2.4f", floor(deg), fmod(deg*60,60), fmod(deg*3600,60));
884 }
885
886 #ifdef AVOID_FLOAT
887 static int tab_atan[]={0,262,524,787,1051,1317,1584,1853,2126,2401,2679,2962,3249,3541,3839,4142,4452,4770,5095,5430,5774,6128,6494,6873,7265,7673,8098,8541,9004,9490,10000,10538};
888
889 static int
890 atan2_int_lookup(int val)
891 {
892         int len=sizeof(tab_atan)/sizeof(int);
893         int i=len/2;
894         int p=i-1;
895         for (;;) {
896                 i>>=1;
897                 if (val < tab_atan[p])
898                         p-=i;
899                 else
900                         if (val < tab_atan[p+1])
901                                 return p+(p>>1);
902                         else
903                                 p+=i;
904         }
905 }
906
907 static int
908 atan2_int(int dx, int dy)
909 {
910         int f,mul=1,add=0,ret;
911         if (! dx) {
912                 return dy < 0 ? 180 : 0;
913         }
914         if (! dy) {
915                 return dx < 0 ? -90 : 90;
916         }
917         if (dx < 0) {
918                 dx=-dx;
919                 mul=-1;
920         }
921         if (dy < 0) {
922                 dy=-dy;
923                 add=180*mul;
924                 mul*=-1;
925         }
926         while (dx > 20000 || dy > 20000) {
927                 dx/=10;
928                 dy/=10;
929         }
930         if (dx > dy) {
931                 ret=90-atan2_int_lookup(dy*10000/dx);
932         } else {
933                 ret=atan2_int_lookup(dx*10000/dy);
934         }
935         return ret*mul+add;
936 }
937 #endif
938
939 int
940 transform_get_angle_delta(struct coord *c1, struct coord *c2, int dir)
941 {
942         int dx=c2->x-c1->x;
943         int dy=c2->y-c1->y;
944 #ifndef AVOID_FLOAT 
945         double angle;
946         angle=atan2(dx,dy);
947         angle*=180/M_PI;
948 #else
949         int angle;
950         angle=atan2_int(dx,dy);
951 #endif
952         if (dir == -1)
953                 angle=angle-180;
954         if (angle < 0)
955                 angle+=360;
956         return angle;
957 }
958
959 int
960 transform_within_border(struct transformation *this_, struct point *p, int border)
961 {
962         struct map_selection *ms=this_->screen_sel;
963         while (ms) {
964                 struct point_rect *r=&ms->u.p_rect;
965                 if (p->x >= r->lu.x+border && p->x <= r->rl.x-border &&
966                     p->y >= r->lu.y+border && p->y <= r->rl.y-border)
967                         return 1;
968                 ms=ms->next;
969         }
970         return 0;
971 }
972
973 int
974 transform_within_dist_point(struct coord *ref, struct coord *c, int dist)
975 {
976         if (c->x-dist > ref->x)
977                 return 0;
978         if (c->x+dist < ref->x)
979                 return 0;
980         if (c->y-dist > ref->y)
981                 return 0;
982         if (c->y+dist < ref->y)
983                 return 0;
984         if ((c->x-ref->x)*(c->x-ref->x) + (c->y-ref->y)*(c->y-ref->y) <= dist*dist) 
985                 return 1;
986         return 0;
987 }
988
989 int
990 transform_within_dist_line(struct coord *ref, struct coord *c0, struct coord *c1, int dist)
991 {
992         int vx,vy,wx,wy;
993         int n1,n2;
994         struct coord lc;
995
996         if (c0->x < c1->x) {
997                 if (c0->x-dist > ref->x)
998                         return 0;
999                 if (c1->x+dist < ref->x)
1000                         return 0;
1001         } else {
1002                 if (c1->x-dist > ref->x)
1003                         return 0;
1004                 if (c0->x+dist < ref->x)
1005                         return 0;
1006         }
1007         if (c0->y < c1->y) {
1008                 if (c0->y-dist > ref->y)
1009                         return 0;
1010                 if (c1->y+dist < ref->y)
1011                         return 0;
1012         } else {
1013                 if (c1->y-dist > ref->y)
1014                         return 0;
1015                 if (c0->y+dist < ref->y)
1016                         return 0;
1017         }
1018         vx=c1->x-c0->x;
1019         vy=c1->y-c0->y;
1020         wx=ref->x-c0->x;
1021         wy=ref->y-c0->y;
1022
1023         n1=vx*wx+vy*wy;
1024         if ( n1 <= 0 )
1025                 return transform_within_dist_point(ref, c0, dist);
1026         n2=vx*vx+vy*vy;
1027         if ( n2 <= n1 )
1028                 return transform_within_dist_point(ref, c1, dist);
1029
1030         lc.x=c0->x+vx*n1/n2;
1031         lc.y=c0->y+vy*n1/n2;
1032         return transform_within_dist_point(ref, &lc, dist);
1033 }
1034
1035 int
1036 transform_within_dist_polyline(struct coord *ref, struct coord *c, int count, int close, int dist)
1037 {
1038         int i;
1039         for (i = 0 ; i < count-1 ; i++) {
1040                 if (transform_within_dist_line(ref,c+i,c+i+1,dist)) {
1041                         return 1;
1042                 }
1043         }
1044         if (close)
1045                 return (transform_within_dist_line(ref,c,c+count-1,dist));
1046         return 0;
1047 }
1048
1049 int
1050 transform_within_dist_polygon(struct coord *ref, struct coord *c, int count, int dist)
1051 {
1052         int i, j, ci = 0;
1053         for (i = 0, j = count-1; i < count; j = i++) {
1054                 if ((((c[i].y <= ref->y) && ( ref->y < c[j].y )) ||
1055                 ((c[j].y <= ref->y) && ( ref->y < c[i].y))) &&
1056                 (ref->x < (c[j].x - c[i].x) * (ref->y - c[i].y) / (c[j].y - c[i].y) + c[i].x))
1057                         ci = !ci;
1058         }
1059         if (! ci) {
1060                 if (dist)
1061                         return transform_within_dist_polyline(ref, c, count, dist, 1);
1062                 else
1063                         return 0;
1064         }
1065         return 1;
1066 }
1067
1068 int
1069 transform_within_dist_item(struct coord *ref, enum item_type type, struct coord *c, int count, int dist)
1070 {
1071         if (type < type_line)
1072                 return transform_within_dist_point(ref, c, dist);
1073         if (type < type_area)
1074                 return transform_within_dist_polyline(ref, c, count, 0, dist);
1075         return transform_within_dist_polygon(ref, c, count, dist);
1076 }
1077
1078 void
1079 transform_destroy(struct transformation *t)
1080 {
1081         g_free(t);
1082 }
1083
1084
1085 /*
1086 Note: there are many mathematically equivalent ways to express these formulas. As usual, not all of them are computationally equivalent.
1087
1088 L = latitude in radians (positive north)
1089 Lo = longitude in radians (positive east)
1090 E = easting (meters)
1091 N = northing (meters)
1092
1093 For the sphere
1094
1095 E = r Lo
1096 N = r ln [ tan (pi/4 + L/2) ]
1097
1098 where 
1099
1100 r = radius of the sphere (meters)
1101 ln() is the natural logarithm
1102
1103 For the ellipsoid
1104
1105 E = a Lo
1106 N = a * ln ( tan (pi/4 + L/2) * ( (1 - e * sin (L)) / (1 + e * sin (L))) ** (e/2)  )
1107
1108
1109                                                e
1110                                                -
1111                    pi     L     1 - e sin(L)   2
1112     =  a ln( tan( ---- + ---) (--------------)   )
1113                    4      2     1 + e sin(L) 
1114
1115
1116 where
1117
1118 a = the length of the semi-major axis of the ellipsoid (meters)
1119 e = the first eccentricity of the ellipsoid
1120
1121
1122 */
1123
1124