00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "vpgl_utm.h"
00011 #include <vcl_iostream.h>
00012 #include <vcl_limits.h>
00013 #include <vnl/vnl_math.h>
00014 #define DBLLONG 4.61168601e18
00015 #define EPSLN 1.0e-10
00016 #define D2R 1.745329251994328e-2
00017 #define MAX_VAL 4
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 static double scale_factor2;
00049 static double es2, esp2;
00050 static double ml02;
00051 static double false_easting2;
00052 static double false_northing2 ;
00053 static int ind2;
00054 static double e02,e12,e22,e32;
00055
00056
00057
00058 static inline int sign(double x) { return (x < 0.0) ? -1 : 1;}
00059
00060 static inline double sqr(double x) { return x*x; }
00061
00062
00063
00064 static double adjust_lon2(double x)
00065 {
00066 for (long count = 0; count <= MAX_VAL; ++count)
00067 {
00068 if (vnl_math_abs(x)<=vnl_math::pi)
00069 break;
00070 else if (long(vnl_math_abs(x / (vnl_math::pi))) < 2)
00071 x -= (sign(x) * 2*vnl_math::pi);
00072 else if (long(vnl_math_abs(x / (2*vnl_math::pi))) < vcl_numeric_limits<long>::max())
00073 x -= long((x /(2*vnl_math::pi))*2*vnl_math::pi);
00074 else if (((long) vnl_math_abs(x / (vcl_numeric_limits<long>::max() * 2*vnl_math::pi))) < vcl_numeric_limits<long>::max())
00075 x -= (((long)(x / (vcl_numeric_limits<long>::max() * 2*vnl_math::pi))) * (2*vnl_math::pi * vcl_numeric_limits<long>::max()));
00076 else if (((long) vnl_math_abs(x / (DBLLONG * 2*vnl_math::pi))) < vcl_numeric_limits<long>::max())
00077 x -= (((long)(x / (DBLLONG * 2*vnl_math::pi))) * (2*vnl_math::pi * DBLLONG));
00078 else
00079 x -= (sign(x) *2*vnl_math::pi);
00080 }
00081
00082 return x;
00083 }
00084
00085 static double adjust_lat2(double x)
00086 {
00087 for (long count = 0; count <= MAX_VAL; ++count)
00088 {
00089 if (vnl_math_abs(x)<=vnl_math::pi_over_2)
00090 break;
00091 else if (((long) vnl_math_abs(x / vnl_math::pi_over_2)) < 2)
00092 x -= (sign(x) * vnl_math::pi);
00093 else if (((long) vnl_math_abs(x / vnl_math::pi)) < vcl_numeric_limits<long>::max())
00094 x -= (((long)(x / vnl_math::pi))*vnl_math::pi);
00095 else if (((long) vnl_math_abs(x / (vcl_numeric_limits<long>::max() * vnl_math::pi))) < vcl_numeric_limits<long>::max())
00096 x -= (((long)(x / (vcl_numeric_limits<long>::max() * vnl_math::pi))) * (vnl_math::pi * vcl_numeric_limits<long>::max()));
00097 else if (((long) vnl_math_abs(x / (DBLLONG * vnl_math::pi))) < vcl_numeric_limits<long>::max())
00098 x -= (((long)(x / (DBLLONG * vnl_math::pi))) * (vnl_math::pi * DBLLONG));
00099 else
00100 x -= (sign(x) *vnl_math::pi);
00101 }
00102
00103 return x;
00104 }
00105
00106
00107
00108
00109 static inline double mlfn2(double e0, double e1, double e2, double e3, double phi)
00110 {
00111 return e0*phi-e1*vcl_sin(2.0*phi)+e2*vcl_sin(4.0*phi)-e3*vcl_sin(6.0*phi);
00112 }
00113
00114
00115
00116 static void UTM_init2(double lat_center2, double r_major, double e, int south_flag)
00117 {
00118 scale_factor2 = 0.9996;
00119
00120 es2 = (double) e * (double) e;
00121 e02 = 1.0-0.25*es2*(1.0+es2/16.0*(3.0+1.25*es2));
00122 e12 = 0.375*es2*(1.0+0.25*es2*(1.0+0.46875*es2));
00123 e22 = 0.05859375*es2*es2*(1.0+0.75*es2);
00124 e32 = es2*es2*es2*(35.0/3072.0);
00125 esp2 = es2/(1.0 - es2);
00126 ml02 = r_major * mlfn2(e02, e12, e22, e32, lat_center2);
00127 false_easting2 = 500000.0;
00128
00129 false_northing2 = (south_flag) ? 10000000.0 : 0.0;
00130
00131 if (es2 < .00001)
00132 ind2 = 1;
00133 else
00134 ind2 = 0;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 vpgl_utm::vpgl_utm()
00144 : a_(6378137), b_(6356752.3142)
00145 {}
00146
00147 vpgl_utm::vpgl_utm(const vpgl_utm& t)
00148 : a_(t.a_), b_(t.b_)
00149 {}
00150
00151 vpgl_utm::~vpgl_utm()
00152 {}
00153
00154
00155 void vpgl_utm::transform(int utm_zone, double x, double y, double z,
00156 double& lat, double& lon , double& elev,
00157 bool south_flag,
00158 double utm_central_meridian)
00159 {
00160
00161 double e = vcl_sqrt((sqr(a_) - sqr(b_))/sqr(a_));
00162
00163 if (utm_zone != 0)
00164 utm_central_meridian = (6 * utm_zone) - 183;
00165
00166 double lon_center2 = adjust_lon2(utm_central_meridian * D2R);
00167 double lat_center2 = 0.0;
00168
00169 double lambda, phi;
00170
00171 UTM_init2(lat_center2, a_, e, south_flag);
00172
00173 double con,temp_phi;
00174 double delta_phi;
00175 long i;
00176 double sin_phi, cos_phi, tan_phi;
00177 double c, cs, t, ts, n, r, d, ds;
00178 double f, h, g, temp;
00179 long max_iter = 6;
00180
00181 if (ind2 != 0)
00182 {
00183 f = vcl_exp(x/(a_ * scale_factor2));
00184 g = .5 * (f - 1/f);
00185 temp = lat_center2 + y/(a_ * scale_factor2);
00186 h = vcl_cos(temp);
00187 con = vcl_sqrt((1.0 - h * h)/(1.0 + g * g));
00188 if (vnl_math_abs(con) > 1.0)
00189 {
00190 if (con > 1.0)
00191 phi = vcl_asin(1.0);
00192 else
00193 phi = vcl_asin(-1.0);
00194 }
00195 else
00196 phi = vcl_asin(con);
00197
00198 if (temp < 0)
00199 phi = -phi;
00200 if ((g == 0) && (h == 0))
00201 {
00202 lambda = lon_center2;
00203 }
00204 else
00205 {
00206 lambda = adjust_lon2(vcl_atan2(g,h) + lon_center2);
00207 }
00208 }
00209 else
00210 {
00211 x -= false_easting2;
00212 y -= false_northing2;
00213
00214 con = (ml02 + y / scale_factor2) / a_;
00215 temp_phi = con;
00216 for (i=0;;i++)
00217 {
00218 delta_phi =
00219 ((con + e12 * vcl_sin(2.0*temp_phi) - e22 * vcl_sin(4.0*temp_phi) + e32 *
00220 vcl_sin(6.0*temp_phi)) / e02) - temp_phi;
00221 #if 0
00222 delta_phi = ((con + e12 * vcl_sin(2.0*phi) - e22 * vcl_sin(4.0*phi)) / e02) - phi;
00223 #endif
00224 temp_phi += delta_phi;
00225
00226 if (vnl_math_abs(delta_phi)<1E-6) break;
00227
00228 if (i >= max_iter)
00229 vcl_cout << "Transform failed to converge" << vcl_endl;
00230 }
00231
00232 if (vnl_math_abs(temp_phi) < vnl_math::pi_over_2)
00233 {
00234 sin_phi = vcl_sin(temp_phi);
00235 cos_phi = vcl_cos(temp_phi);
00236 tan_phi = vcl_tan(temp_phi);
00237 c = esp2 * sqr(cos_phi);
00238 cs = sqr(c);
00239 t = sqr(tan_phi);
00240 ts = sqr(t);
00241 con = 1.0 - es2 * sqr(sin_phi);
00242 n = a_ / vcl_sqrt(con);
00243 r = n * (1.0 - es2) / con;
00244 d = x / (n * scale_factor2);
00245 ds = sqr(d);
00246 phi =
00247 temp_phi - (n * tan_phi * ds / r) *
00248 (0.5 - ds / 24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 *
00249 esp2 - ds / 30.0 * (61.0 + 90.0 * t + 298.0 *
00250 c + 45.0 * ts - 252.0 *
00251 esp2 - 3.0 * cs)));
00252 lambda =
00253 adjust_lon2(lon_center2 +
00254 (d * (1.0 - ds / 6.0 * (1.0 + 2.0 * t + c - ds / 20.0
00255 * (5.0 - 2.0 * c + 28.0 * t -
00256 3.0 * cs + 8.0 * esp2 +
00257 24.0 * ts))) / cos_phi));
00258 }
00259 else
00260 {
00261 phi = vnl_math::pi_over_2 * sign(y);
00262 lambda = lon_center2;
00263 }
00264 }
00265
00266 lat = phi/D2R; lon = lambda/D2R, elev = z;
00267 }
00268
00269 void vpgl_utm::transform(int utm_zone, double x, double y,
00270 double& lat, double& lon,
00271 bool south_flag,
00272 double utm_central_meridian)
00273 {
00274 double elev;
00275 this->transform(utm_zone, x, y, 0.0,
00276 lat, lon, elev,
00277 south_flag, utm_central_meridian);
00278 if (elev) { }
00279 }
00280
00281 void vpgl_utm::transform(double lat, double lon,
00282 double& x, double& y, int& utm_zone)
00283 {
00284
00285 utm_zone = int((lon+180)/6.0) + 1;
00286 double e = vcl_sqrt(1.0 - b_*b_/(a_*a_));
00287
00288
00289 int south_flag;
00290 double utm_central_meridian = 0;
00291
00292 utm_central_meridian = (6 * utm_zone) - 183;
00293
00294 south_flag = lat<0;
00295
00296 double lon_center = adjust_lon2(utm_central_meridian * D2R);
00297 double lat_center = 0.0;
00298
00299 double phi = adjust_lat2(lat*D2R);
00300 double lambda = adjust_lon2(lon*D2R);
00301
00302 UTM_init2(lat_center, a_, e, south_flag);
00303
00304
00305
00306 double delta_lon = adjust_lon2(lambda - lon_center);
00307
00308 double sin_phi = vcl_sin(phi);
00309 double cos_phi = vcl_cos(phi);
00310
00311 double al = cos_phi * delta_lon;
00312 double als = sqr(al);
00313 double c = esp2 * sqr(cos_phi);
00314 double tq = vcl_tan(phi);
00315 double t = sqr(tq);
00316 double con = 1.0 - es2 * sqr(sin_phi);
00317 double n = a_ / vcl_sqrt(con);
00318 double ml = a_ * mlfn2(e02, e12, e22, e32, phi);
00319
00320 x = scale_factor2 * n * al * (1.0 + (als / 6.0) *
00321 (1.0 - t + c + (als / 20.0) *
00322 (5.0 - (18.0 * t) + sqr(t) + (72.0 * c)
00323 - (58.0 * esp2))))
00324 + false_easting2;
00325
00326 y = scale_factor2 * (ml - ml02 + n * tq * (als * (0.5 + (als / 24.0) *
00327 (5.0 - t + (9.0 * c)
00328 + (4.0 * sqr(c))
00329 + (als / 30.0) *
00330 (61.0 - (58.0 * t) +
00331 sqr(t) +
00332 (600.0 * c) -
00333 330.0 * esp2)))))
00334 + false_northing2;
00335 }