Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <ros/ros.h>
00039 #include <angles/angles.h>
00040 #include <geodesy/utm.h>
00041
00055 namespace geodesy
00056 {
00057
00058
00059 #define WGS84_A 6378137.0 // major axis
00060 #define WGS84_B 6356752.31424518 // minor axis
00061 #define WGS84_F 0.0033528107 // ellipsoid flattening
00062 #define WGS84_E 0.0818191908 // first eccentricity
00063 #define WGS84_EP 0.0820944379 // second eccentricity
00064
00065
00066 #define UTM_K0 0.9996 // scale factor
00067 #define UTM_FE 500000.0 // false easting
00068 #define UTM_FN_N 0.0 // false northing, northern hemisphere
00069 #define UTM_FN_S 10000000.0 // false northing, southern hemisphere
00070 #define UTM_E2 (WGS84_E*WGS84_E) // e^2
00071 #define UTM_E4 (UTM_E2*UTM_E2) // e^4
00072 #define UTM_E6 (UTM_E4*UTM_E2) // e^6
00073 #define UTM_EP2 (UTM_E2/(1-UTM_E2)) // e'^2
00074
00075
00082 static char UTMBand(double Lat, double Lon)
00083 {
00084 char LetterDesignator;
00085
00086 if ((84 >= Lat) && (Lat >= 72)) LetterDesignator = 'X';
00087 else if ((72 > Lat) && (Lat >= 64)) LetterDesignator = 'W';
00088 else if ((64 > Lat) && (Lat >= 56)) LetterDesignator = 'V';
00089 else if ((56 > Lat) && (Lat >= 48)) LetterDesignator = 'U';
00090 else if ((48 > Lat) && (Lat >= 40)) LetterDesignator = 'T';
00091 else if ((40 > Lat) && (Lat >= 32)) LetterDesignator = 'S';
00092 else if ((32 > Lat) && (Lat >= 24)) LetterDesignator = 'R';
00093 else if ((24 > Lat) && (Lat >= 16)) LetterDesignator = 'Q';
00094 else if ((16 > Lat) && (Lat >= 8)) LetterDesignator = 'P';
00095 else if (( 8 > Lat) && (Lat >= 0)) LetterDesignator = 'N';
00096 else if (( 0 > Lat) && (Lat >= -8)) LetterDesignator = 'M';
00097 else if ((-8 > Lat) && (Lat >= -16)) LetterDesignator = 'L';
00098 else if((-16 > Lat) && (Lat >= -24)) LetterDesignator = 'K';
00099 else if((-24 > Lat) && (Lat >= -32)) LetterDesignator = 'J';
00100 else if((-32 > Lat) && (Lat >= -40)) LetterDesignator = 'H';
00101 else if((-40 > Lat) && (Lat >= -48)) LetterDesignator = 'G';
00102 else if((-48 > Lat) && (Lat >= -56)) LetterDesignator = 'F';
00103 else if((-56 > Lat) && (Lat >= -64)) LetterDesignator = 'E';
00104 else if((-64 > Lat) && (Lat >= -72)) LetterDesignator = 'D';
00105 else if((-72 > Lat) && (Lat >= -80)) LetterDesignator = 'C';
00106
00107 else LetterDesignator = ' ';
00108
00109 return LetterDesignator;
00110 }
00111
00119 geographic_msgs::GeoPoint toMsg(const UTMPoint &from)
00120 {
00121
00122 double x = from.easting - 500000.0;
00123 double y = from.northing;
00124
00125 double k0 = UTM_K0;
00126 double a = WGS84_A;
00127 double eccSquared = UTM_E2;
00128 double eccPrimeSquared;
00129 double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared));
00130 double N1, T1, C1, R1, D, M;
00131 double LongOrigin;
00132 double mu, phi1Rad;
00133
00134 if ((from.band - 'N') < 0)
00135 {
00136
00137
00138 y -= 10000000.0;
00139 }
00140
00141
00142 LongOrigin = (from.zone - 1)*6 - 180 + 3;
00143 eccPrimeSquared = (eccSquared)/(1-eccSquared);
00144
00145 M = y / k0;
00146 mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64
00147 -5*eccSquared*eccSquared*eccSquared/256));
00148
00149 phi1Rad = mu + ((3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
00150 + (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
00151 + (151*e1*e1*e1/96)*sin(6*mu));
00152
00153 N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad));
00154 T1 = tan(phi1Rad)*tan(phi1Rad);
00155 C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad);
00156 R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5);
00157 D = x/(N1*k0);
00158
00159
00160 geographic_msgs::GeoPoint to;
00161 to.altitude = from.altitude;
00162 to.latitude =
00163 phi1Rad - ((N1*tan(phi1Rad)/R1)
00164 *(D*D/2
00165 -(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24
00166 +(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared
00167 -3*C1*C1)*D*D*D*D*D*D/720));
00168 to.latitude = angles::to_degrees(to.latitude);
00169 to.longitude = ((D-(1+2*T1+C1)*D*D*D/6
00170 +(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1)
00171 *D*D*D*D*D/120)
00172 / cos(phi1Rad));
00173 to.longitude = LongOrigin + angles::to_degrees(to.longitude);
00174
00175
00176 normalize(to);
00177 return to;
00178 }
00179
00187 void fromMsg(const geographic_msgs::GeoPoint &from, UTMPoint &to)
00188 {
00189 double Lat = from.latitude;
00190 double Long = from.longitude;
00191
00192 double a = WGS84_A;
00193 double eccSquared = UTM_E2;
00194 double k0 = UTM_K0;
00195
00196 double LongOrigin;
00197 double eccPrimeSquared;
00198 double N, T, C, A, M;
00199
00200
00201
00202 double LongTemp = (Long+180)-int((Long+180)/360)*360-180;
00203 double LatRad = angles::from_degrees(Lat);
00204 double LongRad = angles::from_degrees(LongTemp);
00205 double LongOriginRad;
00206
00207 to.altitude = from.altitude;
00208 to.zone = int((LongTemp + 180)/6) + 1;
00209
00210 if( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
00211 to.zone = 32;
00212
00213
00214 if( Lat >= 72.0 && Lat < 84.0 )
00215 {
00216 if( LongTemp >= 0.0 && LongTemp < 9.0 ) to.zone = 31;
00217 else if( LongTemp >= 9.0 && LongTemp < 21.0 ) to.zone = 33;
00218 else if( LongTemp >= 21.0 && LongTemp < 33.0 ) to.zone = 35;
00219 else if( LongTemp >= 33.0 && LongTemp < 42.0 ) to.zone = 37;
00220 }
00221
00222 LongOrigin = (to.zone - 1)*6 - 180 + 3;
00223 LongOriginRad = angles::from_degrees(LongOrigin);
00224
00225
00226 to.band = UTMBand(Lat, LongTemp);
00227 #if 0
00228 if (to.band == ' ')
00229 throw std::range_error;
00230 #endif
00231
00232 eccPrimeSquared = (eccSquared)/(1-eccSquared);
00233
00234 N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
00235 T = tan(LatRad)*tan(LatRad);
00236 C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
00237 A = cos(LatRad)*(LongRad-LongOriginRad);
00238
00239 M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64
00240 - 5*eccSquared*eccSquared*eccSquared/256) * LatRad
00241 - (3*eccSquared/8 + 3*eccSquared*eccSquared/32
00242 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
00243 + (15*eccSquared*eccSquared/256
00244 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
00245 - (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
00246
00247 to.easting = (double)
00248 (k0*N*(A+(1-T+C)*A*A*A/6
00249 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
00250 + 500000.0);
00251
00252 to.northing = (double)
00253 (k0*(M+N*tan(LatRad)
00254 *(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
00255 + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
00256
00257 if(Lat < 0)
00258 {
00259
00260 to.northing += 10000000.0;
00261 }
00262 }
00263
00265 bool isValid(const UTMPoint &pt)
00266 {
00267 if (pt.zone < 1 || pt.zone > 60)
00268 return false;
00269
00270 if (!isupper(pt.band) || pt.band == 'I' || pt.band == 'O')
00271 return false;
00272
00273
00274
00275
00276 if (pt.band < 'C' || pt.band > 'X')
00277 return false;
00278
00279 return true;
00280 }
00281
00283 UTMPoint::UTMPoint(const geographic_msgs::GeoPoint &pt)
00284 {
00285 fromMsg(pt, *this);
00286 }
00287
00295 void fromMsg(const geographic_msgs::GeoPose &from, UTMPose &to)
00296 {
00297 fromMsg(from.position, to.position);
00298 to.orientation = from.orientation;
00299 }
00300
00302 bool isValid(const UTMPose &pose)
00303 {
00304 if (!isValid(pose.position))
00305 return false;
00306
00307
00308 double len2 = (pose.orientation.x * pose.orientation.x
00309 + pose.orientation.y * pose.orientation.y
00310 + pose.orientation.z * pose.orientation.z
00311 + pose.orientation.w * pose.orientation.w);
00312 return fabs(len2 - 1.0) <= tf::QUATERNION_TOLERANCE;
00313 }
00314
00315 }