]> err.no Git - mapper/blob - src/latlon.c
Move some variables around
[mapper] / src / latlon.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  *
6  * Original Algorithms from misc web sites
7  *
8  * Default map data provided by http://www.openstreetmap.org/
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 /*
26  * Different Lat/Lon and related functions
27  * (conversion, distances, etc)
28  */
29 #include "config.h"
30
31 #include <math.h>
32 #include <glib.h>
33 #include <glib/gi18n.h>
34
35 #include "latlon.h"
36 #include "osm.h"
37
38 /* Int ranges for integerized lat/lon */
39 #define LATLON_MAX 2147483646
40 #define LATLON_MIN -2147483646
41
42 #define EARTH_RADIUS (3440.06479f)
43
44 void
45 latlon_init(void)
46 {
47 DEG_FORMAT_TEXT[DDPDDDDD] = "-dd.ddddd°";
48 DEG_FORMAT_TEXT[DD_MMPMMM] = "-dd°mm.mmm'";
49 DEG_FORMAT_TEXT[DD_MM_SSPS] = "-dd°mm'ss.s\"";
50 DEG_FORMAT_TEXT[DDPDDDDD_NSEW] = "dd.ddddd° S";
51 DEG_FORMAT_TEXT[DD_MMPMMM_NSEW] = "dd°mm.mmm' S";
52 DEG_FORMAT_TEXT[DD_MM_SSPS_NSEW] = "dd°mm'ss.s\" S";
53
54 UNITS_TEXT[UNITS_KM] = _("km");
55 UNITS_TEXT[UNITS_MI] = _("mi.");
56 UNITS_TEXT[UNITS_NM] = _("n.m.");
57 }
58
59 static inline gdouble 
60 magnitude(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
61 {
62 gdouble x,y;
63 x=x2-x1;
64 y=y2-y1;
65
66 return sqrt((x*x)+(y*y));
67 }
68
69 gboolean 
70 distance_point_to_line(gdouble x, gdouble y, gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble *d)
71 {
72 gdouble lm,u,tmp;
73 gdouble ix,iy;
74
75 lm=magnitude(x1,y1,x2,y2);
76 if (lm==0.0f)
77         return FALSE;
78
79 tmp=((x-x1)*(x2-x1))+((y-y1)*(y2-y1));
80 u=tmp/(lm*lm);
81
82 if (u<0.0f || u>1.0f)
83         return FALSE;
84  
85 ix=x1+u*(x2-x1);
86 iy=y1+u*(y2-y1);
87  
88 *d=magnitude(x,y, ix, iy);
89  
90 return TRUE;
91 }
92
93 /*
94  * QuadTile calculation functions, from:
95  * http://trac.openstreetmap.org/browser/sites/rails_port/lib/quad_tile/quad_tile.h 
96  */
97 guint32 
98 xy2tile(guint x, guint y)
99 {
100 guint32 tile=0;
101 gint i;
102
103 for (i=15;i>=0;i--) {
104         tile=(tile << 1) | ((x >> i) & 1);
105         tile=(tile << 1) | ((y >> i) & 1);
106 }
107 return tile;
108 }
109
110 guint32
111 lon2x(gdouble lon)
112 {
113 return round((lon + 180.0) * 65535.0 / 360.0);
114 }
115
116 guint32 
117 lat2y(gdouble lat)
118 {
119 return round((lat + 90.0) * 65535.0 / 180.0);
120 }
121
122 /* 
123  * Convert latitude to integerized+mercator projected value 
124  */
125 gint32
126 lat2mp_int(gdouble lat)
127 {
128 return lat > 85.051128779 ? LATLON_MAX : lat < -85.051128779 ? LATLON_MIN :
129         lrint(log(tan(M_PI_4l+lat*M_PIl/360))/M_PIl*LATLON_MAX);
130 }
131
132 /* 
133  * Convert longitude to integerized+mercator projected value 
134  */
135 gint32
136 lon2mp_int(gdouble lon)
137 {
138 return lrint(lon/180*LATLON_MAX);
139 }
140
141 gdouble
142 mp_int2lon(gint lon)
143 {
144 return (gdouble)lon/LATLON_MAX*180;
145 }
146
147 gdouble
148 mp_int2lat(gint lat)
149 {
150 return 0;
151 }
152
153 /**
154  * Quick distance calculation, (does not handle earth curvature, so use for quick non exact needs only)
155  */
156 gulong
157 calculate_idistance(gint lat1, gint lon1, gint lat2, gint lon2)
158 {
159 return lrint(sqrt((double)((lat1-lat2)*(lat1-lat2)+(lon1-lon2)*(lon1-lon2))));
160 }
161
162 gdouble
163 calculate_ddistance(gint lat1, gint lon1, gint lat2, gint lon2)
164 {
165 return sqrt((double)((lat1-lat2)*(lat1-lat2)+(lon1-lon2)*(lon1-lon2)));
166 }
167
168 /**
169  * Quick distance for comparing, skips the final square root
170  */
171 gulong
172 calculate_idistance_cmp(gint lat1, gint lon1, gint lat2, gint lon2)
173 {
174 return ((lat1-lat2)*(lat1-lat2)+(lon1-lon2)*(lon1-lon2));
175 }
176
177 /**
178  * Calculate the distance between two lat/lon pairs.
179  * The distance is returned in kilometers.
180  *
181  */
182 gdouble
183 calculate_distance(gdouble lat1, gdouble lon1, gdouble lat2, gdouble lon2)
184 {
185 gdouble dlat, dlon, slat, slon, a;
186
187 /* Convert to radians. */
188 lat1*=(M_PIl / 180.f);
189 lon1*=(M_PIl / 180.f);
190 lat2*=(M_PIl / 180.f);
191 lon2*=(M_PIl / 180.f);
192
193 dlat=lat2 - lat1;
194 dlon=lon2 - lon1;
195
196 slat=sin(dlat / 2.f);
197 slon=sin(dlon / 2.f);
198
199 a=(slat * slat) + (cos(lat1) * cos(lat2) * slon * slon);
200
201 return ((2.f * atan2(sqrt(a), sqrt(1.f - a))) * EARTH_RADIUS);
202 }
203
204 /**
205  * Calculate course from lat1,lon1 to lat2,lon2
206  *
207  */
208 gdouble
209 calculate_course(gdouble lat1, gdouble lon1, gdouble lat2, gdouble lon2)
210 {
211 gdouble c,dlon,x,y;
212
213 lat1*=(M_PIl / 180.f);
214 lon1*=(M_PIl / 180.f);
215 lat2*=(M_PIl / 180.f);
216 lon2*=(M_PIl / 180.f);
217
218 dlon=lon2-lon1;
219 y=sin(dlon)*cos(lat2);
220 x=cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(dlon);
221 c=atan2(y,x);
222
223 /* Fixup for compass */
224 c*=180.f/M_PIl;
225 c=c+360 % 360;
226 return c;
227 }
228
229 void
230 deg_format(DegFormat degformat, gdouble coor, gchar * scoor, gchar neg_char, gchar pos_char)
231 {
232 gdouble min;
233 gdouble acoor=fabs(coor);
234
235 switch (degformat) {
236         case DDPDDDDD:
237                 g_sprintf(scoor, "%.5f°", coor);
238                 break;
239         case DDPDDDDD_NSEW:
240                 g_sprintf(scoor, "%.5f° %c", acoor,
241                         coor < 0.f ? neg_char : pos_char);
242                 break;
243
244         case DD_MMPMMM:
245                 g_sprintf(scoor, "%d°%06.3f'",
246                         (int)coor, (acoor - (int)acoor) * 60.0);
247                 break;
248         case DD_MMPMMM_NSEW:
249                 g_sprintf(scoor, "%d°%06.3f' %c",
250                         (int)acoor, (acoor - (int)acoor) * 60.0,
251                         coor < 0.f ? neg_char : pos_char);
252                 break;
253
254         case DD_MM_SSPS:
255                 min = (acoor - (int)acoor) * 60.0;
256                 g_sprintf(scoor, "%d°%02d'%04.1f\"", (int)coor, (int)min,
257                         ((min - (int)min) * 60.0));
258                 break;
259         case DD_MM_SSPS_NSEW:
260                 min = (acoor - (int)acoor) * 60.0;
261                 g_sprintf(scoor, "%d°%02d'%04.1f\" %c", (int)acoor, (int)min,
262                         ((min - (int)min) * 60.0),
263                         coor < 0.f ? neg_char : pos_char);
264                 break;
265         default:;
266 }
267 }
268