ADORe
ADORe is a modular open source software library and toolkit for decision making, planning, control and simulation of automated vehicles
coordinateconversion.h
Go to the documentation of this file.
1 /********************************************************************************
2  * Copyright (C) 2017-2020 German Aerospace Center (DLR).
3  * Eclipse ADORe, Automated Driving Open Research https://eclipse.org/adore
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License 2.0 which is available at
7  * http://www.eclipse.org/legal/epl-2.0.
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  * Reza Deriani - initial API and implementation
13  ********************************************************************************/
14 
15 #pragma once
16 #include <math.h>
21 //https://de.wikipedia.org/wiki/World_Geodetic_System_1984
22 //http://alephnull.net/software/gis/UTM_WGS84_C_plus_plus.shtml
23 //https://www.springer.com/de/book/9783211835340
24 // Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J. GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994
25 //Germany has 3 different UTM zones see: http://www.killetsoft.de/t_0901_d.htm
26 
27 #define sm_a 6378137.0 //Ellipsoid model major axis
28 #define sm_b 6356752.314 //Ellipsoid model minor axis
29 #define sm_EccSquared 6.69437999013e-03
30 #define UTMScaleFactor 0.9996
31 #define PI 3.14159265358979
32 namespace adore
33 {
34  namespace mad
35  {
37  {
38 
39  public:
47  static int LatLonToUTMXY (double lat, double lon, int zone, double& x, double& y)
48  {
49  if ( (zone < 1) || (zone > 60) )
50  zone = int(std::floor((lon + 180.0) / 6)) + 1;
51 
52  MapLatLonToXY (DegToRad(lat), DegToRad(lon), UTMCentralMeridian(zone), x, y);
53 
54  /* Adjust easting and northing for UTM system. */
55  x = x * UTMScaleFactor + 500000.0;
56  y = y * UTMScaleFactor;
57  if (y < 0.0)
58  y = y + 10000000.0;
59  return zone;
60  }
70  static void UTMXYToLatLon (double x, double y, int zone, bool southhemi, double& lat, double& lon) //zone - The UTM zone in which the point lies, southhemi - True if the point is in the southern hemisphere; false otherwise.
71  {
72  // If the position is in the northern hemisphere then southhemi should be set to false
73  // If the position is in the southern hemisphere then southhemi should be set to true
74  double cmeridian;
75  x -= 500000.0;
76  x /= UTMScaleFactor;
77 
78  /* If in southern hemisphere, adjust y accordingly. */
79  if (southhemi)
80  {
81  y -= 10000000.0;
82  }
83 
84  y /= UTMScaleFactor;
85 
86  cmeridian = UTMCentralMeridian (zone);
87  MapXYToLatLon (x, y, cmeridian, lat, lon);
88  }
98  static void UTMXYToLatLonDegree (double x, double y, int zone, bool southhemi, double& lat, double& lon) //zone - The UTM zone in which the point lies, southhemi - True if the point is in the southern hemisphere; false otherwise.
99  {
100  CoordinateConversion::UTMXYToLatLon (x, y, zone, southhemi, lat, lon) ;
101  lat = RadToDeg (lat);
102  lon = RadToDeg (lon);
103  }
109  static double DegToRad(double deg)
110  {
111  return (deg / 180.00 * PI);
112  }
118  static double RadToDeg(double rad)
119  {
120  return (rad / PI * 180.00);
121  }
127  static double twoPIrange(double rad)
128  {
129  double eps = 1.0e-9;
130  if(rad >= 0 && rad <= 2*PI - eps)
131  {
132  return rad;
133  }
134  else
135  {
136  if(rad > (2*PI - eps) && rad < (2*PI + eps) )
137  {
138  rad = 0.0;
139  }
140  if(rad > 2*PI)
141  {
142  rad -= 2*PI;
143  }
144  if(rad < 0)
145  {
146  rad += 2*PI;
147  }
148  return twoPIrange (rad);
149  }
150  }
151 
152  private:
153  static double ArcLengthOfMeridian (double phi) //returns the ellipsoidal distance of the point from the equator, in meters
154  {
155  double alpha, beta, gamma, delta, epsilon, n;
156  double result;
157 
158  /* Precalculate n */
159  n = (sm_a - sm_b) / (sm_a + sm_b);
160  double n2 = n*n;
161  double n3 = n2*n;
162  double n4 = n3*n;
163  double n5 = n4*n;
164  /* Precalculate alpha */
165  alpha = ((sm_a + sm_b) / 2.0)
166  * (1.0 + ((n2) / 4.0) + ((n4) / 64.0));
167 
168  /* Precalculate beta */
169  beta = (-3.0 * n / 2.0) + (9.0 * (n3) / 16.0)
170  + (-3.0 * (n5) / 32.0);
171 
172  /* Precalculate gamma */
173  gamma = (15.0 * (n2) / 16.0)
174  + (-15.0 * (n4) / 32.0);
175 
176  /* Precalculate delta */
177  delta = (-35.0 * (n3) / 48.0)
178  + (105.0 * (n5) / 256.0);
179 
180  /* Precalculate epsilon */
181  epsilon = (315.0 * (n4) / 512.0);
182 
183  /* Now calculate the sum of the series and return */
184  result = alpha
185  * (phi + (beta * std::sin(2.0 * phi))
186  + (gamma * std::sin(4.0 * phi))
187  + (delta * std::sin(6.0 * phi))
188  + (epsilon * std::sin(8.0 * phi)));
189 
190  return result;
191  }
192  static double UTMCentralMeridian(int zone) //returns the central meridian for the given UTM zone, in radians. Range of the central meridian is the radian equivalent of [-177,+177].
193  {
194  double cmeridian;
195  cmeridian = DegToRad(-183.0 + ((double)zone * 6.0));
196  return cmeridian;
197  }
198  static double FootpointLatitude(double y) //returns the footpoint latitude, in radians
199  {
200  double y_, alpha_, beta_, gamma_, delta_, epsilon_, n;
201  double result;
202 
203  /* Precalculate n (Eq. 10.18) */
204  n = (sm_a - sm_b) / (sm_a + sm_b);
205  double n2 = n*n;
206  double n3 = n2*n;
207  double n4 = n3*n;
208  double n5 = n4*n;
209  /* Precalculate alpha_ (Eq. 10.22) */
210  /* (Same as alpha in Eq. 10.17) */
211  alpha_ = ((sm_a + sm_b) / 2.0)
212  * (1 + ((n2) / 4) + ((n4) / 64));
213 
214  /* Precalculate y_ (Eq. 10.23) */
215  y_ = y / alpha_;
216 
217  /* Precalculate beta_ (Eq. 10.22) */
218  beta_ = (3.0 * n / 2.0) + (-27.0 * (n3) / 32.0)
219  + (269.0 * (n5) / 512.0);
220 
221  /* Precalculate gamma_ (Eq. 10.22) */
222  gamma_ = (21.0 * (n2) / 16.0)
223  + (-55.0 * (n4) / 32.0);
224 
225  /* Precalculate delta_ (Eq. 10.22) */
226  delta_ = (151.0 * (n3) / 96.0)
227  + (-417.0 * (n5) / 128.0);
228 
229  /* Precalculate epsilon_ (Eq. 10.22) */
230  epsilon_ = (1097.0 * (n4) / 512.0);
231 
232  /* Now calculate the sum of the series (Eq. 10.21) */
233  result = y_ + (beta_ * std::sin(2.0 * y_))
234  + (gamma_ * std::sin(4.0 * y_))
235  + (delta_ * std::sin(6.0 * y_))
236  + (epsilon_ * std::sin(8.0 * y_));
237 
238  return result;
239  }
240 
241  static void MapLatLonToXY (double phi, double lambda, double lambda0, double &x, double &y)
242  {
243  double N, nu2, ep2, t, t2, l;
244  double l3coef, l4coef, l5coef, l6coef, l7coef, l8coef;
245 
246  /* Precalculate ep2 */
247  ep2 = ((sm_a*sm_a) - (sm_b*sm_b)) / (sm_b*sm_b);
248 
249  /* Precalculate nu2 */
250  nu2 = ep2 * (std::cos(phi)*std::cos(phi));
251 
252  /* Precalculate N */
253  N = (sm_a*sm_a) / (sm_b * std::sqrt(1 + nu2));
254 
255  /* Precalculate t */
256  t = std::tan(phi);
257  t2 = t * t;
258 
259  /* Precalculate l */
260  l = lambda - lambda0;
261 
262  /* Precalculate coefficients for l**n in the equations below
263  so a normal human being can read the expressions for easting
264  and northing
265  -- l**1 and l**2 have coefficients of 1.0 */
266  l3coef = 1.0 - t2 + nu2;
267 
268  l4coef = 5.0 - t2 + 9 * nu2 + 4.0 * (nu2 * nu2);
269 
270  l5coef = 5.0 - 18.0 * t2 + (t2 * t2) + 14.0 * nu2
271  - 58.0 * t2 * nu2;
272 
273  l6coef = 61.0 - 58.0 * t2 + (t2 * t2) + 270.0 * nu2
274  - 330.0 * t2 * nu2;
275 
276  l7coef = 61.0 - 479.0 * t2 + 179.0 * (t2 * t2) - (t2 * t2 * t2);
277 
278  l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 * t2);
279 
280  /* Calculate easting (x) */
281  double cos_phi = std::cos(phi);
282  double cos_phi2 = cos_phi*cos_phi;
283  double cos_phi3 = cos_phi2 * cos_phi;
284  double l2 = l*l;
285  double l3= l2*l;
286  x = N * std::cos(phi) * l
287  + (N / 6.0 * (cos_phi3) * l3coef * (l3))
288  + (N / 120.0 * (cos_phi3*cos_phi2) * l5coef * (l3*l2))
289  + (N / 5040.0 * (cos_phi3*cos_phi3*cos_phi) * l7coef * (l3*l3*l));
290 
291  /* Calculate northing (y) */
292  y = ArcLengthOfMeridian (phi)
293  + (t / 2.0 * N * (cos_phi2) * (l2))
294  + (t / 24.0 * N * (cos_phi2*cos_phi2) * l4coef * (l3*l))
295  + (t / 720.0 * N * (cos_phi3*cos_phi3) * l6coef * (l3*l3))
296  + (t / 40320.0 * N * (cos_phi3*cos_phi3*cos_phi2) * l8coef * (l3*l3*l2));
297 
298  //return;
299  }
300  static void MapXYToLatLon (double x, double y, double lambda0, double& phi, double& lambda)
301  {
302  double phif, Nf, Nfpow, nuf2, ep2, tf, tf2, tf4, cf;
303  double x1frac, x2frac, x3frac, x4frac, x5frac, x6frac, x7frac, x8frac;
304  double x2poly, x3poly, x4poly, x5poly, x6poly, x7poly, x8poly;
305 
306  /* Get the value of phif, the footpoint latitude. */
307  phif = FootpointLatitude (y);
308 
309  /* Precalculate ep2 */
310  ep2 = ((sm_a*sm_a) - (sm_b*sm_b))
311  / (sm_b*sm_b);
312 
313  /* Precalculate cos (phif) */
314  cf = std::cos(phif);
315 
316  /* Precalculate nuf2 */
317  nuf2 = ep2 * (cf*cf);
318 
319  /* Precalculate Nf and initialize Nfpow */
320  Nf = (sm_a*sm_a) / (sm_b * std::sqrt(1 + nuf2));
321  Nfpow = Nf;
322 
323  /* Precalculate tf */
324  tf = std::tan(phif);
325  tf2 = tf * tf;
326  tf4 = tf2 * tf2;
327 
328  /* Precalculate fractional coefficients for x**n in the equations
329  below to simplify the expressions for latitude and longitude. */
330  x1frac = 1.0 / (Nfpow * cf);
331 
332  Nfpow *= Nf; /* now equals Nf**2) */
333  x2frac = tf / (2.0 * Nfpow);
334 
335  Nfpow *= Nf; /* now equals Nf**3) */
336  x3frac = 1.0 / (6.0 * Nfpow * cf);
337 
338  Nfpow *= Nf; /* now equals Nf**4) */
339  x4frac = tf / (24.0 * Nfpow);
340 
341  Nfpow *= Nf; /* now equals Nf**5) */
342  x5frac = 1.0 / (120.0 * Nfpow * cf);
343 
344  Nfpow *= Nf; /* now equals Nf**6) */
345  x6frac = tf / (720.0 * Nfpow);
346 
347  Nfpow *= Nf; /* now equals Nf**7) */
348  x7frac = 1.0 / (5040.0 * Nfpow * cf);
349 
350  Nfpow *= Nf; /* now equals Nf**8) */
351  x8frac = tf / (40320.0 * Nfpow);
352 
353  /* Precalculate polynomial coefficients for x**n.
354  -- x**1 does not have a polynomial coefficient. */
355  x2poly = -1.0 - nuf2;
356 
357  x3poly = -1.0 - 2 * tf2 - nuf2;
358 
359  x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2
360  - 3.0 * (nuf2 *nuf2) - 9.0 * tf2 * (nuf2 * nuf2);
361 
362  x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2;
363 
364  x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2
365  + 162.0 * tf2 * nuf2;
366 
367  x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2);
368 
369  x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2);
370 
371  /* Calculate latitude */
372  phi = phif + x2frac * x2poly * (x * x)
373  + x4frac * x4poly * (x*x*x*x)
374  + x6frac * x6poly * (x*x*x*x*x*x)
375  + x8frac * x8poly * (x*x*x*x*x*x*x*x);
376 
377  /* Calculate longitude */
378  lambda = lambda0 + x1frac * x
379  + x3frac * x3poly * (x*x*x)
380  + x5frac * x5poly * (x*x*x*x*x)
381  + x7frac * x7poly * (x*x*x*x*x*x*x);
382 
383  //return;
384  }
385 
386 
387 
388 
389  };
390  }
391 }
Definition: coordinateconversion.h:37
static void MapLatLonToXY(double phi, double lambda, double lambda0, double &x, double &y)
Definition: coordinateconversion.h:241
static double twoPIrange(double rad)
Definition: coordinateconversion.h:127
static void UTMXYToLatLonDegree(double x, double y, int zone, bool southhemi, double &lat, double &lon)
Definition: coordinateconversion.h:98
static void UTMXYToLatLon(double x, double y, int zone, bool southhemi, double &lat, double &lon)
Definition: coordinateconversion.h:70
static double ArcLengthOfMeridian(double phi)
Definition: coordinateconversion.h:153
static double UTMCentralMeridian(int zone)
Definition: coordinateconversion.h:192
static int LatLonToUTMXY(double lat, double lon, int zone, double &x, double &y)
Definition: coordinateconversion.h:47
static double FootpointLatitude(double y)
Definition: coordinateconversion.h:198
static double DegToRad(double deg)
Definition: coordinateconversion.h:109
static double RadToDeg(double rad)
Definition: coordinateconversion.h:118
static void MapXYToLatLon(double x, double y, double lambda0, double &phi, double &lambda)
Definition: coordinateconversion.h:300
#define UTMScaleFactor
Definition: coordinateconversion.h:30
#define PI
Definition: coordinateconversion.h:31
#define sm_b
Definition: coordinateconversion.h:28
#define sm_a
Definition: coordinateconversion.h:27
const double eps
Definition: cubic_piecewise_function.cpp:16
interval< T > cos(interval< T > x)
Definition: intervalarithmetic.h:225
interval< T > sin(interval< T > x)
Definition: intervalarithmetic.h:204
x
Definition: adore_set_goal.py:30
y
Definition: adore_set_goal.py:31
Definition: areaofeffectconverter.h:20