59 #define WGS84_A 6378137.0 // major axis 60 #define WGS84_B 6356752.31424518 // minor axis 61 #define WGS84_F 0.0033528107 // ellipsoid flattening 62 #define WGS84_E 0.0818191908 // first eccentricity 63 #define WGS84_EP 0.0820944379 // second eccentricity 66 #define UTM_K0 0.9996 // scale factor 67 #define UTM_FE 500000.0 // false easting 68 #define UTM_FN_N 0.0 // false northing, northern hemisphere 69 #define UTM_FN_S 10000000.0 // false northing, southern hemisphere 70 #define UTM_E2 (WGS84_E*WGS84_E) // e^2 71 #define UTM_E4 (UTM_E2*UTM_E2) // e^4 72 #define UTM_E6 (UTM_E4*UTM_E2) // e^6 73 #define UTM_EP2 (UTM_E2/(1-UTM_E2)) // e'^2 82 static char UTMBand(
double Lat,
double Lon)
84 char LetterDesignator;
86 if ((84 >= Lat) && (Lat >= 72)) LetterDesignator =
'X';
87 else if ((72 > Lat) && (Lat >= 64)) LetterDesignator =
'W';
88 else if ((64 > Lat) && (Lat >= 56)) LetterDesignator =
'V';
89 else if ((56 > Lat) && (Lat >= 48)) LetterDesignator =
'U';
90 else if ((48 > Lat) && (Lat >= 40)) LetterDesignator =
'T';
91 else if ((40 > Lat) && (Lat >= 32)) LetterDesignator =
'S';
92 else if ((32 > Lat) && (Lat >= 24)) LetterDesignator =
'R';
93 else if ((24 > Lat) && (Lat >= 16)) LetterDesignator =
'Q';
94 else if ((16 > Lat) && (Lat >= 8)) LetterDesignator =
'P';
95 else if (( 8 > Lat) && (Lat >= 0)) LetterDesignator =
'N';
96 else if (( 0 > Lat) && (Lat >= -8)) LetterDesignator =
'M';
97 else if ((-8 > Lat) && (Lat >= -16)) LetterDesignator =
'L';
98 else if((-16 > Lat) && (Lat >= -24)) LetterDesignator =
'K';
99 else if((-24 > Lat) && (Lat >= -32)) LetterDesignator =
'J';
100 else if((-32 > Lat) && (Lat >= -40)) LetterDesignator =
'H';
101 else if((-40 > Lat) && (Lat >= -48)) LetterDesignator =
'G';
102 else if((-48 > Lat) && (Lat >= -56)) LetterDesignator =
'F';
103 else if((-56 > Lat) && (Lat >= -64)) LetterDesignator =
'E';
104 else if((-64 > Lat) && (Lat >= -72)) LetterDesignator =
'D';
105 else if((-72 > Lat) && (Lat >= -80)) LetterDesignator =
'C';
107 else LetterDesignator =
' ';
109 return LetterDesignator;
127 double eccSquared =
UTM_E2;
128 double eccPrimeSquared;
129 double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared));
130 double N1, T1, C1, R1, D, M;
134 if ((from.
band -
'N') < 0)
142 LongOrigin = (from.
zone - 1)*6 - 180 + 3;
143 eccPrimeSquared = (eccSquared)/(1-eccSquared);
146 mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64
147 -5*eccSquared*eccSquared*eccSquared/256));
149 phi1Rad = mu + ((3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
150 + (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
151 + (151*e1*e1*e1/96)*sin(6*mu));
153 N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad));
154 T1 = tan(phi1Rad)*tan(phi1Rad);
155 C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad);
156 R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5);
160 geographic_msgs::GeoPoint to;
163 phi1Rad - ((N1*tan(phi1Rad)/R1)
165 -(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24
166 +(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared
167 -3*C1*C1)*D*D*D*D*D*D/720));
169 to.longitude = ((D-(1+2*T1+C1)*D*D*D/6
170 +(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1)
188 const bool& force_zone,
const char& band,
const uint8_t& zone)
190 double Lat = from.latitude;
191 double Long = from.longitude;
194 double eccSquared =
UTM_E2;
198 double eccPrimeSquared;
199 double N, T, C, A, M;
203 double LongTemp = (Long+180)-
int((Long+180)/360)*360-180;
206 double LongOriginRad;
210 to.
zone = int((LongTemp + 180)/6) + 1;
214 if( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
218 if( Lat >= 72.0 && Lat < 84.0 )
220 if( LongTemp >= 0.0 && LongTemp < 9.0 ) to.
zone = 31;
221 else if( LongTemp >= 9.0 && LongTemp < 21.0 ) to.
zone = 33;
222 else if( LongTemp >= 21.0 && LongTemp < 33.0 ) to.
zone = 35;
223 else if( LongTemp >= 33.0 && LongTemp < 42.0 ) to.
zone = 37;
226 LongOrigin = (to.
zone - 1)*6 - 180 + 3;
239 throw std::range_error;
242 eccPrimeSquared = (eccSquared)/(1-eccSquared);
244 N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
245 T = tan(LatRad)*tan(LatRad);
246 C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
247 A = cos(LatRad)*(LongRad-LongOriginRad);
249 M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64
250 - 5*eccSquared*eccSquared*eccSquared/256) * LatRad
251 - (3*eccSquared/8 + 3*eccSquared*eccSquared/32
252 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
253 + (15*eccSquared*eccSquared/256
254 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
255 - (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
258 (k0*N*(A+(1-T+C)*A*A*A/6
259 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
264 *(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
265 + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
280 if (!isupper(pt.
band) || pt.
band ==
'I' || pt.
band ==
'O')
305 geographic_msgs::GeoPose to;
319 const bool& force_zone,
const char&
band,
const uint8_t&
zone)
char band
MGRS latitude band letter.
Universal Transverse Mercator coordinates.
void fromMsg(const geographic_msgs::GeoPoint &from, UTMPoint &to, const bool &force_zone=false, const char &band='A', const uint8_t &zone=0)
static const double QUATERNION_TOLERANCE
TFSIMD_FORCE_INLINE const tfScalar & y() const
double northing
northing within grid zone [meters]
double altitude
altitude above ellipsoid [meters] or NaN
geometry_msgs::Quaternion orientation
uint8_t zone
UTM longitude zone number.
static double from_degrees(double degrees)
static double to_degrees(double radians)
TFSIMD_FORCE_INLINE const tfScalar & x() const
static void normalize(UTMPoint &pt)
bool isValid(const UTMPoint &pt)
double easting
easting within grid zone [meters]
geographic_msgs::GeoPoint toMsg(const UTMPoint &from)
static char UTMBand(double Lat, double Lon)