//////////////////////////////////// // C++ による 地図投影法のクラス // //////////////////////////////////// #include "Projection.h" #include "stdlib.h" #include "stdio.h" #include "string.h" #include "math.h" ///////////////////////////////////////////////////////////////////////////// // Projectionクラスの構築子 Projection::Projection() { } ///////////////////////////////////////////////////////////////////////////// // Projectionクラスの消滅子 Projection::~Projection() { } ///////////////////////////////////////////////////////////////////////////// // 文字表現の緯度を実数値に変換して返す // 89 --> 89.000000 // 89.999999 --> 89.999999 // N89 --> 89.000000 // N89.999999 --> 89.999999 // N89.59' --> 89.983333 // N89.59'99 --> 89.999833 // N89.59'59" --> 89.999722 // N89.59'59"99 --> 89.99999722 // -89 --> -89.000000 // -89.999999 --> -89.999999 // S89 --> -89.000000 // S89.999999 --> -89.999999 // S89.59' --> -89.983333 // S89.59'99 --> -89.999833 // S89.59'59" --> -89.999722 // S89.59'59"99 --> -89.99999722 double Projection::ConvLatitudeToDouble( char* Str ) { char *p = Str; int Sign = 1; // Northern=1, Southern=-1 char digits[64]; int cnt = 0; char degrees[64]; // degree char minutes[64]; // minute char seconds[64]; // second BOOL minutesFlg = FALSE; BOOL secondsFlg = FALSE; BOOL fructionMode = FALSE; double value; // latitude if( Str[0] == '\0' ){ return INT_MAX; } memset( digits, 0, sizeof(digits) ); memset( degrees, 0, sizeof(degrees) ); memset( minutes, 0, sizeof(minutes) ); memset( seconds, 0, sizeof(seconds) ); while( *p != '\0' ){ if( ( *p >= '0' )&&( *p <= '9' ) ){ digits[cnt++] = *p; }else if( *p == CHAR_PUNCT ){ if( ( minutesFlg == TRUE )||( secondsFlg == TRUE ) ){ return INT_MAX; // illegal fruction point! } strcpy( degrees, digits ); memset( digits, 0, sizeof(digits) ); cnt = 0; fructionMode = TRUE; }else if( *p == '\'' ){ if( ( minutesFlg == TRUE )||( secondsFlg == TRUE ) ){ return INT_MAX; // illegal order! } minutesFlg = TRUE; strcpy( minutes, digits ); memset( digits, 0, sizeof(digits) ); cnt = 0; fructionMode = TRUE; }else if( *p == '\"' ){ if( secondsFlg == TRUE ){ return INT_MAX; // illegal order! } secondsFlg = TRUE; strcpy( seconds, digits ); memset( digits, 0, sizeof(digits) ); cnt = 0; fructionMode = TRUE; }else if( *p == 'N' ){ // Northern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = 1; }else if( *p == 'S' ){ // Southern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = -1; }else if( *p == '+' ){ // Northern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = 1; }else if( *p == '-' ){ // Southern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = -1; }else if( ( *p == ' ' )||( *p == '\t' ) ){ // 空白 if( cnt > 0 ){ return INT_MAX; // illegal space } }else{ return INT_MAX; } p++; } if( cnt > 0 ){ if( fructionMode == TRUE ){ if( secondsFlg == TRUE ){ seconds[strlen(seconds)] = CHAR_PUNCT; strcat(seconds, digits ); }else if( minutesFlg == TRUE ){ minutes[strlen(minutes)] = CHAR_PUNCT; strcat(minutes, digits ); }else if( ( minutesFlg == FALSE )&&( secondsFlg == FALSE ) ){ degrees[strlen(degrees)] = CHAR_PUNCT; strcat(degrees, digits ); } }else{ if( ( minutesFlg == FALSE )&&( secondsFlg == FALSE ) ){ strcpy( degrees, digits ); } } } value = atof(degrees) + (atof(minutes) / 60 ) + ( atof(seconds) / 3600 ); value *= Sign; return value; } ///////////////////////////////////////////////////////////////////////////// // 文字表現の経度を実数値に変換して返す // 179 --> 179.000000 // 179.999999 --> 179.999999 // E179 --> 179.000000 // E179.999999 --> 179.999999 // E179.59' --> 179.983333 // E179.59'99 --> 179.999833 // E179.59'59" --> 179.999722 // E179.59'59"99 --> 179.99999722 // -179 --> -179.000000 // -179.999999 --> -179.999999 // W179 --> -179.000000 // W179.999999 --> -179.999999 // W179.59' --> -179.983333 // W179.59'99 --> -179.999833 // W179.59'59" --> -179.999722 // W179.59'59"99 --> -179.99999722 double Projection::ConvLongitudeToDouble( char* Str ) { char *p = Str; int Sign = 1; // Eastern=1, Western=-1 char digits[64]; int cnt = 0; char degrees[64]; // degree char minutes[64]; // minute char seconds[64]; // second BOOL minutesFlg = FALSE; BOOL secondsFlg = FALSE; BOOL fructionMode = FALSE; double value; // latitude if( Str[0] == '\0' ){ return INT_MAX; } memset( digits, 0, sizeof(digits) ); memset( degrees, 0, sizeof(degrees) ); memset( minutes, 0, sizeof(minutes) ); memset( seconds, 0, sizeof(seconds) ); while( *p != '\0' ){ if( ( *p >= '0' )&&( *p <= '9' ) ){ digits[cnt++] = *p; }else if( *p == CHAR_PUNCT ){ if( ( minutesFlg == TRUE )||( secondsFlg == TRUE ) ){ return INT_MAX; // illegal fruction point! } strcpy( degrees, digits ); memset( digits, 0, sizeof(digits) ); cnt = 0; fructionMode = TRUE; }else if( *p == '\'' ){ if( ( minutesFlg == TRUE )||( secondsFlg == TRUE ) ){ return INT_MAX; // illegal order! } minutesFlg = TRUE; strcpy( minutes, digits ); memset( digits, 0, sizeof(digits) ); cnt = 0; fructionMode = TRUE; }else if( *p == '\"' ){ if( secondsFlg == TRUE ){ return INT_MAX; // illegal order! } secondsFlg = TRUE; strcpy( seconds, digits ); memset( digits, 0, sizeof(digits) ); cnt = 0; fructionMode = TRUE; }else if( *p == 'E' ){ // Northern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = 1; }else if( *p == 'W' ){ // Southern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = -1; }else if( *p == '+' ){ // Eastern if( p != Str ){ return INT_MAX; // expect as top char! } Sign = 1; }else if( *p == '-' ){ // Western if( p != Str ){ return INT_MAX; // expect as top char! } Sign = -1; }else if( ( *p == ' ' )||( *p == '\t' ) ){ // 空白 if( cnt > 0 ){ return INT_MAX; // illegal space } }else{ return INT_MAX; } p++; } if( cnt > 0 ){ if( fructionMode == TRUE ){ if( secondsFlg == TRUE ){ seconds[strlen(seconds)] = CHAR_PUNCT; strcat(seconds, digits ); }else if( minutesFlg == TRUE ){ minutes[strlen(minutes)] = CHAR_PUNCT; strcat(minutes, digits ); }else if( ( minutesFlg == FALSE )&&( secondsFlg == FALSE ) ){ degrees[strlen(degrees)] = CHAR_PUNCT; strcat(degrees, digits ); } }else{ if( ( minutesFlg == FALSE )&&( secondsFlg == FALSE ) ){ strcpy( degrees, digits ); } } } value = atof(degrees) + (atof(minutes) / 60 ) + ( atof(seconds) / 3600 ); value *= Sign; return value; } ///////////////////////////////////////////////////////////////////////////// // 経緯度をランベルト正積図法(Lambert Azimuthal equal-area projection)の座標系に変換 // IN/ lon 経度の実数値 (度単位) // IN/ lat 緯度の実数値 (度単位) // IN/ lon0 ランベルト正積図法の中心経度 (度単位) // IN/ lat0 ランベルト正積図法の中心緯度 (度単位) // /OUT *x 求められたX座標 -1.0 〜 +1.0 地球の半径を掛けると実距離になる ) // /OUT *y 求められたY座標 -1.0 〜 +1.0 地球の半径を掛けると実距離になる ) void Projection::GeoToLea( double lon, double lat, double lon0, double lat0, double *x, double *y ) { double phi; // latitude radian double phi1; double lamda; // longitude radian double lamda0; double pi = 3.14159265358979; double k; phi = lat * pi / 180.0; phi1 = lat0 * pi / 180.0; lamda = lon * pi / 180.0; lamda0 = lon0 * pi / 180.0; k = 2 / ( 1 + sin(phi1) * sin(phi) + cos(phi1) * cos(phi) * cos(lamda-lamda0) ); if( k > 0 ){ k = sqrt(k); }else{ k = 0; } *x = k * cos(phi) * sin(lamda - lamda0); *y = k * ( cos(phi1) * sin(phi) - sin(phi1) * cos(phi) * cos(lamda-lamda0) ); } ///////////////////////////////////////////////////////////////////////////// // LEA座標系をマップ画像の位置に変換 POINT Projection::ConvLeaToMapXy( double x, double y, double shift_x, double shift_y, double magnify ) { POINT pnt; pnt.x = (long)(( x + shift_x ) * magnify); pnt.y = (long)(( y * (-1) + shift_y) * magnify); return pnt; } ///////////////////////////////////////////////////////////////////////////// // メートル単位の距離をLEA座標系のピクセル数に換算 double Projection::lengthLEA( int length, double magnify ) { return ( (double)length * magnify / 6365000.0 ); } ///////////////////////////////////////////////////////////////////////////// // 経緯度を横メルカトル図法(Transverse Mercator's projection)の座標系に変換 // IN/ lon 経度の実数値 (度単位) // IN/ lat 緯度の実数値 (度単位) // IN/ lon0 横メルカトル図法の中心経度 (度単位) // /OUT *x 求められたX座標 中心経線からの距離 メートル単位) // /OUT *y 求められたY座標 赤道からの距離 メートル単位) void Projection::GeoToTM( double lon, double lat, double lon0, double *x, double *y ) { double phi; // latitude radian double lamda; // longitude radian double pi = 3.14159265358979; double a = 6378137; double f = 1 / 298.2572336; double k0 = 0.9996; double lamda0; double e2; double E2; double n; double M; double T; double C; double A; phi = lat * pi / 180.0; lamda = lon * pi / 180.0; //// ユニバーサル横メルカトル図法ではないので、ゾーンで分けない //// int zone; //// zone = ( (int)( lon + 180 ) ) / 6 + 1; //// lamda0 = ( ( zone - 1 ) * 6 - 180 + 3 ) * pi / 180.0; lamda0 = lon0 * pi / 180.0; // center longitude e2 = 2 * ( f - f * f ); E2 = e2 / ( 1 - e2 ); //// b = a * sqrt( 1 - e2 ); n = a / sqrt( 1 - e2 * sin(phi) * sin(phi) ); M = a * ( ( 1 - e2/4 - 3*e2*e2/64 - 5*e2*e2*e2/256 ) * phi - ( 3*e2/8 + 3*e2*e2/32 + 45*e2*e2*e2/1024 ) * sin(2*phi) + ( 15*e2*e2/256 + 45*e2*e2*e2/1024 ) * sin(4*phi) - ( 35*e2*e2*e2/3072 ) * sin(6*phi) ); T = tan(phi) * tan(phi); C = E2 * cos(phi) * cos(phi); A = ( lamda - lamda0 ) * cos(phi); *x = k0 * n * ( A + (1-T+C)*A*A*A/6 + (5 - 18*T + T*T + 72*C - 58*E2)*A*A*A*A*A*120 ) ; ////+ 500000; // ユニバーサル横メルカトル図法ではないので、経線方向にシフトさせない。X座標は負値あり *y = k0 * ( M + n * tan(phi) * ( A*A/2 + ( 5 - T + 9*C + 4*C*C) * A*A*A*A*24 + ( 61 - 58 * T + T*T + 600*C - 330*E2) * A*A*A*A*A*A*720 ) ); } ///////////////////////////////////////////////////////////////////////////// // TM座標系をマップ画像の位置に変換 POINT Projection::ConvTMToMapXy( double x, double y, double shift_x, double shift_y, double magnify ) { POINT pnt; pnt.x = (long)(( x + shift_x ) * magnify); pnt.y = (long)(( y * (-1) + shift_y) * magnify); return pnt; } ///////////////////////////////////////////////////////////////////////////// // メートル単位の距離をTM座標系のピクセル数に換算 double Projection::lengthTM( int length, double magnify ) { return ( (double)length * magnify ); }