116 using namespace MSP::CCS;
 
  124 const double PI = 3.14159265358979323e0;  
 
  137 ObliqueMercator::ObliqueMercator( 
double ellipsoidSemiMajorAxis, 
double ellipsoidFlattening, 
double originLatitude, 
double longitude1, 
double latitude1, 
double longitude2, 
double latitude2, 
double falseEasting, 
double falseNorthing, 
double scaleFactor ) :
 
  139   es( 0.08181919084262188000 ),
 
  140   es_OVER_2( .040909595421311 ),
 
  141   OMerc_A( 6383471.9177251 ),
 
  142   OMerc_B( 1.0008420825413 ),
 
  143   OMerc_E( 1.0028158089754 ),
 
  144   OMerc_gamma( .41705894983580 ),
 
  145   OMerc_azimuth( .60940407333533 ),
 
  146   OMerc_Origin_Long( -.46732023406900 ),
 
  147   cos_gamma( .91428423352628 ),
 
  148   sin_gamma( .40507325303611 ),
 
  149   sin_azimuth( .57237890829911 ),  
 
  150   cos_azimuth( .81998925927985 ),
 
  151   A_over_B( 6378101.0302010 ),
 
  152   B_over_A( 1.5678647849335e-7 ),
 
  153   OMerc_u( 5632885.2272051 ),
 
  154   OMerc_Origin_Lat( ((45.0 * 
PI) / 180.0) ),
 
  155   OMerc_Lon_1( ((-5.0 * 
PI) / 180.0) ),
 
  156   OMerc_Lat_1( ((40.0 * 
PI) / 180.0) ),
 
  157   OMerc_Lon_2( ((5.0 * 
PI) / 180.0) ),
 
  158   OMerc_Lat_2( ((50.0 * 
PI) / 180.0) ),
 
  159   OMerc_False_Easting( 0.0 ),
 
  160   OMerc_False_Northing( 0.0 ),
 
  161   OMerc_Scale_Factor( 1.0 ),
 
  162   OMerc_Delta_Northing( 40000000.0 ),
 
  163   OMerc_Delta_Easting(  40000000.0 )
 
  192   double inv_f = 1 / ellipsoidFlattening;
 
  193   double es2, one_MINUS_es2;
 
  194   double cos_olat, cos_olat2;
 
  195   double sin_olat, sin_olat2, es2_sin_olat2;
 
  197   double D, D2, D2_MINUS_1, sqrt_D2_MINUS_1;
 
  203   if (ellipsoidSemiMajorAxis <= 0.0)
 
  207   if ((inv_f < 250) || (inv_f > 350))
 
  223   if (latitude1 == 0.0)
 
  227   if (latitude1 == latitude2)
 
  231   if (((latitude1 < 0.0) && (latitude2 > 0.0)) ||
 
  232       ((latitude1 > 0.0) && (latitude2 < 0.0)))
 
  236   if ((longitude1 < -
PI) || (longitude1 > 
TWO_PI))
 
  240   if ((longitude2 < -
PI) || (longitude2 > 
TWO_PI))
 
  252   OMerc_Origin_Lat = originLatitude;
 
  253   OMerc_Lon_1 = longitude1;
 
  254   OMerc_Lat_1 = latitude1;
 
  255   OMerc_Lon_2 = longitude2;
 
  256   OMerc_Lat_2 = latitude2;
 
  257   OMerc_False_Northing = falseNorthing;
 
  258   OMerc_False_Easting = falseEasting;
 
  259   OMerc_Scale_Factor = scaleFactor;
 
  263   one_MINUS_es2 = 1 - es2;
 
  264   es_OVER_2 = es / 2.0;
 
  266   cos_olat = cos(OMerc_Origin_Lat);
 
  267   cos_olat2 = cos_olat * cos_olat;
 
  268   sin_olat = sin(OMerc_Origin_Lat);
 
  269   sin_olat2 = sin_olat * sin_olat;
 
  270   es2_sin_olat2 = es2 * sin_olat2;
 
  272   OMerc_B = sqrt(1 + (es2 * cos_olat2 * cos_olat2) / one_MINUS_es2);
 
  273   OMerc_A = (
semiMajorAxis * OMerc_B * OMerc_Scale_Factor * sqrt(one_MINUS_es2)) / (1.0 - es2_sin_olat2);  
 
  274   A_over_B = OMerc_A / OMerc_B;
 
  275   B_over_A = OMerc_B / OMerc_A;
 
  277   t0 = omercT(OMerc_Origin_Lat, es * sin_olat, es_OVER_2);
 
  278   t1 = omercT(OMerc_Lat_1, es * sin(OMerc_Lat_1), es_OVER_2);  
 
  279   t2 = omercT(OMerc_Lat_2, es * sin(OMerc_Lat_2), es_OVER_2);  
 
  281   D = (OMerc_B * sqrt(one_MINUS_es2)) / (cos_olat * sqrt(1.0 - es2_sin_olat2)); 
 
  285   D2_MINUS_1 = D2 - 1.0;
 
  286   sqrt_D2_MINUS_1 = sqrt(D2_MINUS_1);
 
  287   if (D2_MINUS_1 > 1.0e-10)
 
  289     if (OMerc_Origin_Lat >= 0.0)
 
  290       OMerc_E = (D + sqrt_D2_MINUS_1) * pow(t0, OMerc_B);
 
  292       OMerc_E = (D - sqrt_D2_MINUS_1) * pow(t0, OMerc_B);
 
  295     OMerc_E = D * pow(t0, OMerc_B);
 
  296   H = pow(t1, OMerc_B);
 
  297   L = pow(t2, OMerc_B);
 
  299   G = (F - 1.0 / F) / 2.0;
 
  300   E2 = OMerc_E * OMerc_E;
 
  302   J = (E2 - LH) / (E2 + LH);
 
  303   P = (L - H) / (L + H);
 
  305   dlon = OMerc_Lon_1 - OMerc_Lon_2;
 
  310   dlon = OMerc_Lon_1 - OMerc_Lon_2;
 
  311   OMerc_Origin_Long = (OMerc_Lon_1 + OMerc_Lon_2) / 2.0 - (atan(J * tan(OMerc_B * dlon / 2.0) / P)) / OMerc_B;
 
  313   dlon = OMerc_Lon_1 - OMerc_Origin_Long;
 
  315     OMerc_Origin_Long -= 
TWO_PI;
 
  317     OMerc_Origin_Long += 
TWO_PI;
 
  319   dlon = OMerc_Lon_1 - OMerc_Origin_Long;
 
  320   OMerc_gamma = atan(sin(OMerc_B * dlon) / G);
 
  321   cos_gamma = cos(OMerc_gamma);
 
  322   sin_gamma = sin(OMerc_gamma);
 
  324   OMerc_azimuth = asin(D * sin_gamma);
 
  325   cos_azimuth = cos(OMerc_azimuth);
 
  326   sin_azimuth = sin(OMerc_azimuth);
 
  328   if (OMerc_Origin_Lat >= 0)
 
  329     OMerc_u =  A_over_B * atan(sqrt_D2_MINUS_1/cos_azimuth);
 
  331     OMerc_u = -A_over_B * atan(sqrt_D2_MINUS_1/cos_azimuth);
 
  340   es_OVER_2 = om.es_OVER_2;     
 
  341   OMerc_A = om.OMerc_A;     
 
  342   OMerc_B = om.OMerc_B;     
 
  343   OMerc_E = om.OMerc_E;     
 
  344   OMerc_gamma = om.OMerc_gamma; 
 
  345   OMerc_azimuth = om.OMerc_azimuth; 
 
  346   OMerc_Origin_Long = om.OMerc_Origin_Long; 
 
  347   cos_gamma = om.cos_gamma; 
 
  348   sin_gamma = om.sin_gamma; 
 
  349   sin_azimuth = om.sin_azimuth; 
 
  350   cos_azimuth = om.cos_azimuth; 
 
  351   A_over_B = om.A_over_B; 
 
  352   B_over_A = om.B_over_A; 
 
  353   OMerc_u = om.OMerc_u; 
 
  354   OMerc_Origin_Lat = om.OMerc_Origin_Lat; 
 
  355   OMerc_Lon_1 = om.OMerc_Lon_1; 
 
  356   OMerc_Lat_1 = om.OMerc_Lat_1; 
 
  357   OMerc_Lon_2 = om.OMerc_Lon_2; 
 
  358   OMerc_Lat_2 = om.OMerc_Lat_2; 
 
  359   OMerc_False_Easting = om.OMerc_False_Easting; 
 
  360   OMerc_False_Northing = om.OMerc_False_Northing; 
 
  361   OMerc_Scale_Factor = om.OMerc_Scale_Factor; 
 
  362   OMerc_Delta_Northing = om.OMerc_Delta_Northing; 
 
  363   OMerc_Delta_Easting = om.OMerc_Delta_Easting; 
 
  379     es_OVER_2 = om.es_OVER_2;     
 
  380     OMerc_A = om.OMerc_A;     
 
  381     OMerc_B = om.OMerc_B;     
 
  382     OMerc_E = om.OMerc_E;     
 
  383     OMerc_gamma = om.OMerc_gamma; 
 
  384     OMerc_azimuth = om.OMerc_azimuth; 
 
  385     OMerc_Origin_Long = om.OMerc_Origin_Long; 
 
  386     cos_gamma = om.cos_gamma; 
 
  387     sin_gamma = om.sin_gamma; 
 
  388     sin_azimuth = om.sin_azimuth; 
 
  389     cos_azimuth = om.cos_azimuth; 
 
  390     A_over_B = om.A_over_B; 
 
  391     B_over_A = om.B_over_A; 
 
  392     OMerc_u = om.OMerc_u; 
 
  393     OMerc_Origin_Lat = om.OMerc_Origin_Lat; 
 
  394     OMerc_Lon_1 = om.OMerc_Lon_1; 
 
  395     OMerc_Lat_1 = om.OMerc_Lat_1; 
 
  396     OMerc_Lon_2 = om.OMerc_Lon_2; 
 
  397     OMerc_Lat_2 = om.OMerc_Lat_2; 
 
  398     OMerc_False_Easting = om.OMerc_False_Easting; 
 
  399     OMerc_False_Northing = om.OMerc_False_Northing; 
 
  400     OMerc_Scale_Factor = om.OMerc_Scale_Factor; 
 
  401     OMerc_Delta_Northing = om.OMerc_Delta_Northing; 
 
  402     OMerc_Delta_Easting = om.OMerc_Delta_Easting; 
 
  455   double dlam, B_dlam, cos_B_dlam;
 
  456   double t, S, T, V, U;
 
  463   double longitude = geodeticCoordinates->
longitude();
 
  464   double latitude = geodeticCoordinates->
latitude();
 
  470   if ((longitude < -
PI) || (longitude > 
TWO_PI))
 
  475   dlam = longitude - OMerc_Origin_Long;
 
  493   if (fabs(fabs(latitude) - 
PI_OVER_2) > 1.0e-10)
 
  495     t = omercT(latitude, es * sin(latitude), es_OVER_2);  
 
  496     Q = OMerc_E / pow(t, OMerc_B);
 
  498     S = (Q - Q_inv) / 2.0;
 
  499     T = (Q + Q_inv) / 2.0;
 
  500     B_dlam = OMerc_B * dlam;
 
  502     U = ((-1.0 * V * cos_gamma) + (S * sin_gamma)) / T;
 
  503     if (fabs(fabs(U) - 1.0) < 1.0e-10)
 
  509       v = A_over_B * log((1.0 - U) / (1.0 + U)) / 2.0;
 
  510       cos_B_dlam = cos(B_dlam);
 
  511       if (fabs(cos_B_dlam) < 1.0e-10)
 
  512         u = OMerc_A * B_dlam;
 
  516         double temp = atan(((S * cos_gamma) + (V * sin_gamma)) / cos_B_dlam);
 
  518           u = A_over_B * (temp + 
PI);
 
  520           u = A_over_B * (temp - 
PI);
 
  523         u = A_over_B * atan(((S * cos_gamma) + (V * sin_gamma)) / cos_B_dlam);
 
  529       v = A_over_B * log(tan(
PI_OVER_4 - (OMerc_gamma / 2.0)));
 
  531       v = A_over_B * log(tan(
PI_OVER_4 + (OMerc_gamma / 2.0)));
 
  532     u = A_over_B * latitude;
 
  538   double easting = OMerc_False_Easting + v * cos_azimuth + u * sin_azimuth;
 
  539   double northing = OMerc_False_Northing + u * cos_azimuth - v * sin_azimuth;
 
  565   double Q_prime, Q_prime_inv;
 
  566   double S_prime, T_prime, V_prime, U_prime;
 
  571   double temp_phi = 0.0;
 
  573   double longitude, latitude;
 
  575   double easting  = mapProjectionCoordinates->
easting();
 
  576   double northing = mapProjectionCoordinates->
northing();
 
  578   if ((easting < (OMerc_False_Easting - OMerc_Delta_Easting)) 
 
  579       || (easting > (OMerc_False_Easting + OMerc_Delta_Easting)))
 
  583   if ((northing < (OMerc_False_Northing - OMerc_Delta_Northing)) 
 
  584       || (northing > (OMerc_False_Northing + OMerc_Delta_Northing)))
 
  589   dy = northing - OMerc_False_Northing;
 
  590   dx = easting - OMerc_False_Easting;
 
  591   v = dx * cos_azimuth - dy * sin_azimuth;
 
  592   u = dy * cos_azimuth + dx * sin_azimuth;
 
  594   Q_prime = exp(-1.0 * (v * B_over_A ));
 
  595   Q_prime_inv = 1.0 / Q_prime;
 
  596   S_prime = (Q_prime - Q_prime_inv) / 2.0;
 
  597   T_prime = (Q_prime + Q_prime_inv) / 2.0;
 
  598   u_B_over_A = u * B_over_A;
 
  599   V_prime = sin(u_B_over_A);
 
  600   U_prime = (V_prime * cos_gamma + S_prime * sin_gamma) / T_prime;
 
  601   if (fabs(fabs(U_prime) - 1.0) < 1.0e-10)
 
  607     longitude = OMerc_Origin_Long;
 
  611     t = pow(OMerc_E / sqrt((1.0 + U_prime) / (1.0 - U_prime)), 1.0 / OMerc_B);
 
  613     while (fabs(phi - temp_phi) > 1.0e-10 && count)
 
  616       es_sin = es * sin(phi);
 
  617       phi = 
PI_OVER_2 - 2.0 * atan(t * pow((1.0 - es_sin) / (1.0 + es_sin), es_OVER_2));
 
  625     longitude = OMerc_Origin_Long - atan2((S_prime * cos_gamma - V_prime * sin_gamma), cos(u_B_over_A)) / OMerc_B;
 
  628   if (fabs(latitude) < 2.0e-7)  
 
  640   if (fabs(longitude) < 2.0e-7)  
 
  644   else if (longitude < -
PI)
 
  649   if (fabs(longitude - OMerc_Origin_Long) >= 
PI_OVER_2)
 
  659 double ObliqueMercator::omercT( 
double lat, 
double e_sinlat, 
double e_over_2 )
 
  661   return (tan(
PI_OVER_4 - lat / 2.0)) / (pow((1 - e_sinlat) / (1 + e_sinlat), e_over_2));