navsat_conversions.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2010 Austin Robot Technology, and others
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 * 3. Neither the names of the University of Texas at Austin, nor
16 * Austin Robot Technology, nor the names of other contributors may
17 * be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * This file contains code from multiple files in the original
34 * source. The originals can be found here:
35 *
36 * https://github.com/austin-robot/utexas-art-ros-pkg/blob/afd147a1eb944fc3dbd138574c39699813f797bf/stacks/art_vehicle/art_common/include/art/UTM.h
37 * https://github.com/austin-robot/utexas-art-ros-pkg/blob/afd147a1eb944fc3dbd138574c39699813f797bf/stacks/art_vehicle/art_common/include/art/conversions.h
38 */
39 
40 #ifndef ROBOT_LOCALIZATION_NAVSAT_CONVERSIONS_H
41 #define ROBOT_LOCALIZATION_NAVSAT_CONVERSIONS_H
42 
51 #include <cmath>
52 #include <string>
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 
57 namespace RobotLocalization
58 {
59 namespace NavsatConversions
60 {
61 
62 const double RADIANS_PER_DEGREE = M_PI/180.0;
63 const double DEGREES_PER_RADIAN = 180.0/M_PI;
64 
65 // Grid granularity for rounding UTM coordinates to generate MapXY.
66 const double grid_size = 100000.0; // 100 km grid
67 
68 // WGS84 Parameters
69 #define WGS84_A 6378137.0 // major axis
70 #define WGS84_B 6356752.31424518 // minor axis
71 #define WGS84_F 0.0033528107 // ellipsoid flattening
72 #define WGS84_E 0.0818191908 // first eccentricity
73 #define WGS84_EP 0.0820944379 // second eccentricity
74 
75 // UTM Parameters
76 #define UTM_K0 0.9996 // scale factor
77 #define UTM_FE 500000.0 // false easting
78 #define UTM_FN_N 0.0 // false northing, northern hemisphere
79 #define UTM_FN_S 10000000.0 // false northing, southern hemisphere
80 #define UTM_E2 (WGS84_E*WGS84_E) // e^2
81 #define UTM_E4 (UTM_E2*UTM_E2) // e^4
82 #define UTM_E6 (UTM_E4*UTM_E2) // e^6
83 #define UTM_EP2 (UTM_E2/(1-UTM_E2)) // e'^2
84 
94 static inline void UTM(double lat, double lon, double *x, double *y)
95 {
96  // constants
97  static const double m0 = (1 - UTM_E2/4 - 3*UTM_E4/64 - 5*UTM_E6/256);
98  static const double m1 = -(3*UTM_E2/8 + 3*UTM_E4/32 + 45*UTM_E6/1024);
99  static const double m2 = (15*UTM_E4/256 + 45*UTM_E6/1024);
100  static const double m3 = -(35*UTM_E6/3072);
101 
102  // compute the central meridian
103  int cm = ((lon >= 0.0)
104  ? (static_cast<int>(lon) - (static_cast<int>(lon)) % 6 + 3)
105  : (static_cast<int>(lon) - (static_cast<int>(lon)) % 6 - 3));
106 
107  // convert degrees into radians
108  double rlat = lat * RADIANS_PER_DEGREE;
109  double rlon = lon * RADIANS_PER_DEGREE;
110  double rlon0 = cm * RADIANS_PER_DEGREE;
111 
112  // compute trigonometric functions
113  double slat = sin(rlat);
114  double clat = cos(rlat);
115  double tlat = tan(rlat);
116 
117  // decide the false northing at origin
118  double fn = (lat > 0) ? UTM_FN_N : UTM_FN_S;
119 
120  double T = tlat * tlat;
121  double C = UTM_EP2 * clat * clat;
122  double A = (rlon - rlon0) * clat;
123  double M = WGS84_A * (m0*rlat + m1*sin(2*rlat)
124  + m2*sin(4*rlat) + m3*sin(6*rlat));
125  double V = WGS84_A / sqrt(1 - UTM_E2*slat*slat);
126 
127  // compute the easting-northing coordinates
128  *x = UTM_FE + UTM_K0 * V * (A + (1-T+C)*pow(A, 3)/6
129  + (5-18*T+T*T+72*C-58*UTM_EP2)*pow(A, 5)/120);
130  *y = fn + UTM_K0 * (M + V * tlat * (A*A/2
131  + (5-T+9*C+4*C*C)*pow(A, 4)/24
132  + ((61-58*T+T*T+600*C-330*UTM_EP2)
133  * pow(A, 6)/720)));
134 
135  return;
136 }
137 
138 
147 static inline char UTMLetterDesignator(double Lat)
148 {
149  char LetterDesignator;
150 
151  if ((84 >= Lat) && (Lat >= 72)) LetterDesignator = 'X';
152  else if ((72 > Lat) && (Lat >= 64)) LetterDesignator = 'W';
153  else if ((64 > Lat) && (Lat >= 56)) LetterDesignator = 'V';
154  else if ((56 > Lat) && (Lat >= 48)) LetterDesignator = 'U';
155  else if ((48 > Lat) && (Lat >= 40)) LetterDesignator = 'T';
156  else if ((40 > Lat) && (Lat >= 32)) LetterDesignator = 'S';
157  else if ((32 > Lat) && (Lat >= 24)) LetterDesignator = 'R';
158  else if ((24 > Lat) && (Lat >= 16)) LetterDesignator = 'Q';
159  else if ((16 > Lat) && (Lat >= 8)) LetterDesignator = 'P';
160  else if (( 8 > Lat) && (Lat >= 0)) LetterDesignator = 'N';
161  else if (( 0 > Lat) && (Lat >= -8)) LetterDesignator = 'M';
162  else if ((-8 > Lat) && (Lat >= -16)) LetterDesignator = 'L';
163  else if ((-16 > Lat) && (Lat >= -24)) LetterDesignator = 'K';
164  else if ((-24 > Lat) && (Lat >= -32)) LetterDesignator = 'J';
165  else if ((-32 > Lat) && (Lat >= -40)) LetterDesignator = 'H';
166  else if ((-40 > Lat) && (Lat >= -48)) LetterDesignator = 'G';
167  else if ((-48 > Lat) && (Lat >= -56)) LetterDesignator = 'F';
168  else if ((-56 > Lat) && (Lat >= -64)) LetterDesignator = 'E';
169  else if ((-64 > Lat) && (Lat >= -72)) LetterDesignator = 'D';
170  else if ((-72 > Lat) && (Lat >= -80)) LetterDesignator = 'C';
171  // 'Z' is an error flag, the Latitude is outside the UTM limits
172  else LetterDesignator = 'Z';
173  return LetterDesignator;
174 }
175 
189 static inline void LLtoUTM(const double Lat, const double Long,
190  double &UTMNorthing, double &UTMEasting,
191  std::string &UTMZone, double &gamma)
192 {
193  double a = WGS84_A;
194  double eccSquared = UTM_E2;
195  double k0 = UTM_K0;
196 
197  double LongOrigin;
198  double eccPrimeSquared;
199  double N, T, C, A, M;
200 
201  // Make sure the longitude is between -180.00 .. 179.9
202  double LongTemp = (Long+180)-static_cast<int>((Long+180)/360)*360-180;
203 
204  double LatRad = Lat*RADIANS_PER_DEGREE;
205  double LongRad = LongTemp*RADIANS_PER_DEGREE;
206  double LongOriginRad;
207  int ZoneNumber;
208 
209  ZoneNumber = static_cast<int>((LongTemp + 180)/6) + 1;
210 
211  if ( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
212  ZoneNumber = 32;
213 
214  // Special zones for Svalbard
215  if ( Lat >= 72.0 && Lat < 84.0 )
216  {
217  if ( LongTemp >= 0.0 && LongTemp < 9.0 ) ZoneNumber = 31;
218  else if ( LongTemp >= 9.0 && LongTemp < 21.0 ) ZoneNumber = 33;
219  else if ( LongTemp >= 21.0 && LongTemp < 33.0 ) ZoneNumber = 35;
220  else if ( LongTemp >= 33.0 && LongTemp < 42.0 ) ZoneNumber = 37;
221  }
222  // +3 puts origin in middle of zone
223  LongOrigin = (ZoneNumber - 1)*6 - 180 + 3;
224  LongOriginRad = LongOrigin * RADIANS_PER_DEGREE;
225 
226  // Compute the UTM Zone from the latitude and longitude
227  char zone_buf[] = {0, 0, 0, 0};
228  snprintf(zone_buf, sizeof(zone_buf), "%d%c", ZoneNumber, UTMLetterDesignator(Lat));
229  UTMZone = std::string(zone_buf);
230 
231  eccPrimeSquared = (eccSquared)/(1-eccSquared);
232 
233  N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
234  T = tan(LatRad)*tan(LatRad);
235  C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
236  A = cos(LatRad)*(LongRad-LongOriginRad);
237 
238  M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64
239  - 5*eccSquared*eccSquared*eccSquared/256) * LatRad
240  - (3*eccSquared/8 + 3*eccSquared*eccSquared/32
241  + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
242  + (15*eccSquared*eccSquared/256
243  + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
244  - (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
245 
246  UTMEasting = static_cast<double>
247  (k0*N*(A+(1-T+C)*A*A*A/6
248  + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
249  + 500000.0);
250 
251  UTMNorthing = static_cast<double>
252  (k0*(M+N*tan(LatRad)
253  *(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
254  + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
255 
256  gamma = atan(tan(LongRad-LongOriginRad)*sin(LatRad)) * DEGREES_PER_RADIAN;
257 
258  if (Lat < 0)
259  {
260  // 10000000 meter offset for southern hemisphere
261  UTMNorthing += 10000000.0;
262  }
263 }
264 
274 static inline void LLtoUTM(const double Lat, const double Long,
275  double &UTMNorthing, double &UTMEasting,
276  std::string &UTMZone)
277 {
278  double gamma;
279  LLtoUTM(Lat, Long, UTMNorthing, UTMEasting, UTMZone, gamma);
280 }
281 
295 static inline void UTMtoLL(const double UTMNorthing, const double UTMEasting,
296  const std::string &UTMZone, double& Lat, double& Long, double &gamma)
297 {
298  double k0 = UTM_K0;
299  double a = WGS84_A;
300  double eccSquared = UTM_E2;
301  double eccPrimeSquared;
302  double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared));
303  double N1, T1, C1, R1, D, M;
304  double LongOrigin;
305  double mu, phi1Rad;
306  double x, y;
307  int ZoneNumber;
308  char* ZoneLetter;
309 
310  x = UTMEasting - 500000.0; // remove 500,000 meter offset for longitude
311  y = UTMNorthing;
312 
313  ZoneNumber = strtoul(UTMZone.c_str(), &ZoneLetter, 10);
314  if ((*ZoneLetter - 'N') < 0)
315  {
316  // remove 10,000,000 meter offset used for southern hemisphere
317  y -= 10000000.0;
318  }
319 
320  // +3 puts origin in middle of zone
321  LongOrigin = (ZoneNumber - 1)*6 - 180 + 3;
322  eccPrimeSquared = (eccSquared)/(1-eccSquared);
323 
324  M = y / k0;
325  mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64
326  -5*eccSquared*eccSquared*eccSquared/256));
327 
328  phi1Rad = mu + ((3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
329  + (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
330  + (151*e1*e1*e1/96)*sin(6*mu));
331 
332  N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad));
333  T1 = tan(phi1Rad)*tan(phi1Rad);
334  C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad);
335  R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5);
336  D = x/(N1*k0);
337 
338  Lat = phi1Rad - ((N1*tan(phi1Rad)/R1)
339  *(D*D/2
340  -(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24
341  +(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared
342  -3*C1*C1)*D*D*D*D*D*D/720));
343 
344  Lat = Lat * DEGREES_PER_RADIAN;
345 
346  Long = ((D-(1+2*T1+C1)*D*D*D/6
347  +(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1)
348  *D*D*D*D*D/120)
349  / cos(phi1Rad));
350  Long = LongOrigin + Long * DEGREES_PER_RADIAN;
351 
352  gamma = atan(tanh(x/(k0*a))*tan(y/(k0*a))) * DEGREES_PER_RADIAN;
353 }
354 
364 static inline void UTMtoLL(const double UTMNorthing, const double UTMEasting,
365  const std::string &UTMZone, double& Lat, double& Long)
366 {
367  double gamma;
368  UTMtoLL(UTMNorthing, UTMEasting, UTMZone, Lat, Long, gamma);
369 }
370 
371 } // namespace NavsatConversions
372 } // namespace RobotLocalization
373 
374 #endif // ROBOT_LOCALIZATION_NAVSAT_CONVERSIONS_H
static void UTM(double lat, double lon, double *x, double *y)
INLINE Rall1d< T, V, S > tanh(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > atan(const Rall1d< T, V, S > &x)
static char UTMLetterDesignator(double Lat)
static void LLtoUTM(const double Lat, const double Long, double &UTMNorthing, double &UTMEasting, std::string &UTMZone, double &gamma)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > tan(const Rall1d< T, V, S > &arg)
static void UTMtoLL(const double UTMNorthing, const double UTMEasting, const std::string &UTMZone, double &Lat, double &Long, double &gamma)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)


robot_localization
Author(s): Tom Moore
autogenerated on Wed Feb 3 2021 03:34:02