studio_proj_c.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /**
  2. ******************************************************************************
  3. * @file : studio_proj_c.c
  4. * @author : wyj
  5. * @brief : 高斯投影 C 语言版
  6. * @attention : None
  7. * @date : 2025/5/9
  8. ******************************************************************************
  9. */
  10. #include "studio_proj_c.h"
  11. void lonlat_to_gauss(const double central, const double lon, const double lat, double *gx, double *gy)
  12. {
  13. // 将纬度和经度转换为弧度
  14. double lamb = DEG2RAD_C(lat);
  15. double phi = DEG2RAD_C(lon);
  16. // 将中央子午线转换为弧度
  17. double centralMeridianRad = DEG2RAD_C(central);
  18. // 计算高斯-克吕格投影公式中的参数
  19. double N = WGS84_A_C / sqrt(1 - WGS84_E2_C * sin(lamb) * sin(lamb));
  20. double T = tan(lamb) * tan(lamb);
  21. double C = WGS84_E2_C * cos(lamb) * cos(lamb) / (1 - WGS84_E2_C);
  22. double A = (phi - centralMeridianRad) * cos(lamb);
  23. // 计算子午线弧长
  24. double M = WGS84_A_C * ((1 - WGS84_E2_C / 4.0 - 3.0 * WGS84_E2_C * WGS84_E2_C / 64.0 - 5.0 * WGS84_E2_C * WGS84_E2_C * WGS84_E2_C / 256.0) * lamb -
  25. (3.0 * WGS84_E2_C / 8.0 + 3.0 * WGS84_E2_C * WGS84_E2_C / 32.0 + 45.0 * WGS84_E2_C * WGS84_E2_C * WGS84_E2_C / 1024.0) * sin(2.0 * lamb) +
  26. (15.0 * WGS84_E2_C * WGS84_E2_C / 256.0 + 45.0 * WGS84_E2_C * WGS84_E2_C * WGS84_E2_C / 1024.0) * sin(4.0 * lamb) - (35.0 * WGS84_E2_C * WGS84_E2_C * WGS84_E2_C / 3072.0) * sin(6.0 * lamb));
  27. // 计算 X, Y 坐标
  28. *gy = M + N * tan(lamb) * (A * A / 2.0 + (5.0 - T + 9.0 * C + 4.0 * C * C) * A * A * A * A / 24.0 + (61.0 - 58.0 * T + T * T + 600.0 * C - 330.0 * WGS84_E2_C) * A * A * A * A * A * A / 720.0);
  29. *gx = N * (A + (1.0 - T + C) * A * A * A / 6.0 + (5.0 - 18.0 * T + T * T + 72.0 * C - 58.0 * WGS84_E2_C) * A * A * A * A * A / 120.0) + 500000.0; // 中央子午线偏移+500000.0
  30. }
  31. void gauss_to_lonlat(const double central, const double gx, const double gy, double *lon, double *lat)
  32. {
  33. // 将高斯平面坐标转换为经纬度坐标
  34. double Y = gx;
  35. double X = gy;
  36. // 去除中央经线的偏移量
  37. Y -= 500000;
  38. // 计算第一偏心率的平方根倒数
  39. double e1 = (1 - sqrt(1 - WGS84_E2_C)) / (1 + sqrt(1 - WGS84_E2_C));
  40. // 计算子午线弧长
  41. double M = X;
  42. // 计算子午线曲率半径
  43. double mu = M / (WGS84_A_C * (1 - WGS84_E2_C / 4.0 - 3 * WGS84_E2_C * WGS84_E2_C / 64.0 - 5 * WGS84_E2_C * WGS84_E2_C * WGS84_E2_C / 256.0));
  44. // 计算纬度
  45. double phi1 = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * sin(6 * mu) + (1097 * e1 * e1 * e1 * e1 / 512) * sin(8 * mu);
  46. // 计算子午线曲率半径
  47. double C1 = WGS84_E2_C * cos(phi1) * cos(phi1) / (1 - WGS84_E2_C);
  48. // 计算纬度曲率半径
  49. double T1 = tan(phi1) * tan(phi1);
  50. // 计算卯酉圈曲率半径
  51. double N1 = WGS84_A_C / sqrt(1 - WGS84_E2_C * sin(phi1) * sin(phi1));
  52. // 计算子午线弧长
  53. double R1 = WGS84_A_C * (1 - WGS84_E2_C) / pow(1 - WGS84_E2_C * sin(phi1) * sin(phi1), 1.5);
  54. // 计算子午线弧长
  55. double D = Y / N1;
  56. // 经纬度计算
  57. double phi = phi1 - (N1 * tan(phi1) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * e1) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * e1 - 3 * C1 * C1) * D * D * D * D * D * D / 720);
  58. double lambda = DEG2RAD_C(central) + (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * e1 + 24 * T1 * T1) * D * D * D * D * D / 120) / cos(phi1);
  59. // 转换为度
  60. *lat = RAD2DEG_C(phi);
  61. *lon = RAD2DEG_C(lambda);
  62. }
  63. void lonlat_to_mercator(const double lon, const double lat, double *mctx, double *mcty)
  64. {
  65. // 经度转换:phi = lon * (AO_M_PI / 180.0)
  66. double phi = DEG2RAD_C(lon);
  67. // 纬度转换:lamb = lat * (AO_M_PI / 180.0)
  68. double lamb = DEG2RAD_C(lat);
  69. // 墨卡托投影公式:mctx = WGS84_A_C * phi
  70. *mctx = WGS84_A_C * phi;
  71. // 墨卡托投影公式:mcty = WGS84_A_C * log(tan(AO_M_PI / 4 + lamb / 2))
  72. *mcty = WGS84_A_C * log(tan(AO_M_PI / 4 + lamb / 2));
  73. }
  74. void mercator_to_lonlat(const double mctx, const double mcty, double *lon, double *lat)
  75. {
  76. // 经度转换:mctx / WGS84_A_C
  77. *lon = RAD2DEG_C(mctx / WGS84_A_C);
  78. // 纬度转换:使用逆墨卡托公式
  79. *lat = RAD2DEG_C(2 * atan(exp(mcty / WGS84_A_C)) - AO_M_PI / 2);
  80. }
  81. // 将高斯投影坐标转换为墨卡托投影坐标
  82. void gauss_to_mercator(const double central, const double gx, const double gy, double *mctx, double *mcty)
  83. {
  84. // 定义经度和纬度变量
  85. double lon;
  86. double lat;
  87. // 将高斯投影坐标转换为经纬度坐标
  88. gauss_to_lonlat(central, gx, gy, &lon, &lat);
  89. // 将经纬度坐标转换为墨卡托投影坐标
  90. lonlat_to_mercator(lon, lat, mctx, mcty);
  91. }
  92. // 将墨卡托坐标转换为高斯坐标
  93. void mercator_to_gauss(const double central, const double mctx, const double mcty, double *gx, double *gy)
  94. {
  95. // 定义经纬度变量
  96. double lon;
  97. double lat;
  98. // 将墨卡托坐标转换为经纬度
  99. mercator_to_lonlat(mctx, mcty, &lon, &lat);
  100. // 将经纬度转换为高斯坐标
  101. lonlat_to_gauss(central, lon, lat, gx, gy);
  102. }
  103. void lonlat_to_ecef(const double lon, const double lat, const double height, double* x, double* y, double* z)
  104. {
  105. // 将经纬度转换为弧度
  106. double lamb = DEG2RAD_C(lat);
  107. double phi = DEG2RAD_C(lon);
  108. // 计算N (曲率半径)
  109. double N = WGS84_A_C / sqrt(1 - WGS84_E2_C * sin(lamb) * sin(lamb));
  110. // 计算XYZ坐标
  111. *x = (N + height) * cos(lamb) * cos(phi);
  112. *y = (N + height) * cos(lamb) * sin(phi);
  113. *z = (WGS84_B_C * WGS84_B_C / (WGS84_A_C * WGS84_A_C) * N + height) * sin(lamb);
  114. }
  115. void ecef_to_lonlat(const double x, const double y, const double z, double* lon, double* lat, double* height)
  116. {
  117. // 计算经度
  118. *lon = atan2(y, x);
  119. // 计算初始纬度估计
  120. double p = sqrt(x * x + y * y);
  121. double theta = atan2(z, p * (1 - WGS84_F_C));
  122. *lat = atan2(z + WGS84_E2_C * WGS84_B_C * pow(sin(theta), 3), p - WGS84_E2_C * WGS84_B_C * pow(cos(theta), 3));
  123. // 迭代计算纬度,直到收敛
  124. double previousLatitude;
  125. do
  126. {
  127. previousLatitude = *lat;
  128. double N = WGS84_A_C / sqrt(1 - WGS84_E2_C * sin(*lat) * sin(*lat));
  129. *height = p / cos(*lat) - N;
  130. *lat = atan2(z + WGS84_E2_C * N * sin(*lat), p);
  131. } while (fabs(*lat - previousLatitude) > 1e-12); // 收敛条件
  132. // 将纬度和经度转换为度
  133. *lat = RAD2DEG_C(*lat);
  134. *lon = RAD2DEG_C(*lon);
  135. }