studio_geo_algo_c.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /**
  2. ******************************************************************************
  3. * @file : studio_geo_algo_c.c
  4. * @author : wangyingjie
  5. * @brief : None
  6. * @attention : None
  7. * @date : 2025/5/11
  8. ******************************************************************************
  9. */
  10. #include "studio_geo_algo_c.h"
  11. #include "geography/studio_proj_c.h"
  12. /////////////////// 基础适量算法 ///////////////////
  13. double distance_squared_c(const studio_point_c *p1, const studio_point_c *p2)
  14. {
  15. const double dx = p1->x - p2->x;
  16. const double dy = p1->y - p2->y;
  17. return dx * dx + dy * dy;
  18. }
  19. double point_line_dist_square_c(const studio_point_c *p, const studio_point_c *start, const studio_point_c *end)
  20. {
  21. double A = p->x - start->x;
  22. double B = p->y - start->y;
  23. double C = end->x - start->x;
  24. double D = end->y - start->y;
  25. double dot = A * C + B * D;
  26. double len_sq = C * C + D * D;
  27. double param = len_sq == 0 ? -1 : dot / len_sq;
  28. double xx, yy;
  29. if (param < 0)
  30. {
  31. xx = start->x;
  32. yy = start->y;
  33. }
  34. else if (param > 1)
  35. {
  36. xx = end->x;
  37. yy = end->y;
  38. }
  39. else
  40. {
  41. xx = start->x + param * C;
  42. yy = start->y + param * D;
  43. }
  44. double dist_square = (xx - p->x) * (xx - p->x) + (yy - p->y) * (yy - p->y);
  45. return dist_square;
  46. }
  47. double azimuth_angle_c(const studio_point_c *p_from, const studio_point_c *p_to)
  48. {
  49. double delta_x = p_to->x - p_from->x;
  50. double delta_y = p_to->y - p_from->y;
  51. double theta_rad = atan2(delta_x, delta_y);
  52. double theta_deg = theta_rad * (180.0 / AO_M_PI);
  53. if (theta_deg < 0.0)
  54. {
  55. theta_deg += 360.0;
  56. }
  57. return theta_deg;
  58. }
  59. double distance_squared_gcs_c(const studio_point_c *p1, const studio_point_c *p2)
  60. {
  61. // 经纬度转高斯投影
  62. // double central = ((int) (p1->x) / 3) * 3;
  63. double central = floor((p1->x + 1.5) / 3.0) * 3.0;
  64. double gx_1, gy_1;
  65. lonlat_to_gauss(central, p1->x, p1->y, &gx_1, &gy_1);
  66. studio_point_c gs_p1 = studio_point_init(gx_1, gy_1);
  67. double gx_2, gy_2;
  68. lonlat_to_gauss(central, p2->x, p2->y, &gx_2, &gy_2);
  69. studio_point_c gs_p2 = studio_point_init(gx_2, gy_2);
  70. double dist_square = distance_squared_c(&gs_p1, &gs_p2);
  71. return dist_square;
  72. }
  73. double point_line_dist_square_gcs_c(const studio_point_c *p, const studio_point_c *start, const studio_point_c *end)
  74. {
  75. // 经纬度转高斯投影
  76. // double central = ((int) (p->x) / 3) * 3;
  77. double central = floor((p->x + 1.5) / 3.0) * 3.0;
  78. double gx_p, gy_p;
  79. lonlat_to_gauss(central, p->x, p->y, &gx_p, &gy_p);
  80. studio_point_c gs_p = studio_point_init(gx_p, gy_p);
  81. double gx_start, gy_start;
  82. lonlat_to_gauss(central, start->x, start->y, &gx_start, &gy_start);
  83. studio_point_c gs_start = studio_point_init(gx_start, gy_start);
  84. double gx_end, gy_end;
  85. lonlat_to_gauss(central, end->x, end->y, &gx_end, &gy_end);
  86. studio_point_c gs_end = studio_point_init(gx_end, gy_end);
  87. double dist_square = point_line_dist_square_c(&gs_p, &gs_start, &gs_end);
  88. return dist_square;
  89. }
  90. double azimuth_angle_gcs_c(const studio_point_c *p_from, const studio_point_c *p_to)
  91. {
  92. // 经纬度转高斯投影
  93. // double central = ((int) (p_from->x) / 3) * 3;
  94. double central = floor((p_from->x + 1.5) / 3.0) * 3.0;
  95. double gx_from, gy_from;
  96. lonlat_to_gauss(central, p_from->x, p_from->y, &gx_from, &gy_from);
  97. studio_point_c gs_from = studio_point_init(gx_from, gy_from);
  98. double gx_to, gy_to;
  99. lonlat_to_gauss(central, p_to->x, p_to->y, &gx_to, &gy_to);
  100. studio_point_c gs_to = studio_point_init(gx_to, gy_to);
  101. double theta_deg = azimuth_angle_c(&gs_from, &gs_to);
  102. return theta_deg;
  103. }
  104. studio_point_c lonlat_move_by(const studio_point_c *pt, double delta_x, double delta_y)
  105. {
  106. // 中央经线
  107. double central = floor((pt->x + 1.5) / 3.0) * 3.0;
  108. // 转换为高斯平面坐标
  109. double gx, gy;
  110. lonlat_to_gauss(central, pt->x, pt->y, &gx, &gy);
  111. // 应用平面坐标偏移(东向加delta_x,北向加delta_y)
  112. const double new_gx = gx + delta_x; // 单位:米
  113. const double new_gy = gy + delta_y;
  114. // 转回经纬度
  115. double new_lon, new_lat;
  116. gauss_to_lonlat(central, new_gx, new_gy, &new_lon, &new_lat);
  117. // 经度范围修正(-180~180)
  118. new_lon = fmod(new_lon + 360.0, 360.0); // 先转0~360
  119. if (new_lon > 180.0)
  120. {
  121. new_lon -= 360.0; // 再转-180~180
  122. }
  123. studio_point_c new_point = studio_point_init(new_lon, new_lat);
  124. return new_point;
  125. }
  126. /////////////////// 矢量(线)抽稀算法 ///////////////////
  127. void douglas_peucker_c(const studio_line_c *points, size_t start, size_t end, double epsilon, unsigned int *indices, unsigned int *index_count, unsigned int max_indices)
  128. {
  129. if (end <= start + 1)
  130. {
  131. if (*index_count < max_indices)
  132. {
  133. indices[*index_count] = start;
  134. (*index_count)++;
  135. }
  136. if (start != end && *index_count < max_indices)
  137. {
  138. indices[*index_count] = end;
  139. (*index_count)++;
  140. }
  141. return;
  142. }
  143. double max_dist = 0;
  144. size_t index = start;
  145. double epsilon_square = epsilon * epsilon;
  146. for (size_t i = start + 1; i < end; ++i)
  147. {
  148. double dist_square = point_line_dist_square_c(&points->data[i], &points->data[start], &points->data[end]);
  149. if (dist_square > max_dist)
  150. {
  151. index = i;
  152. max_dist = dist_square;
  153. }
  154. }
  155. if (max_dist > epsilon_square && index > start && index < end)
  156. {
  157. douglas_peucker_c(points, start, index, epsilon, indices, index_count, max_indices);
  158. douglas_peucker_c(points, index, end, epsilon, indices, index_count, max_indices);
  159. }
  160. else
  161. {
  162. if (*index_count < max_indices)
  163. {
  164. indices[*index_count] = start;
  165. (*index_count)++;
  166. }
  167. if (*index_count < max_indices && start != end)
  168. {
  169. indices[*index_count] = end;
  170. (*index_count)++;
  171. }
  172. }
  173. }
  174. void remove_duplicates(unsigned int *indices, unsigned int *index_count)
  175. {
  176. if (*index_count == 0)
  177. {
  178. return;
  179. }
  180. unsigned int j = 0; // 指向去重后的位置
  181. for (unsigned int i = 0; i < *index_count; i++)
  182. {
  183. bool is_duplicate = false;
  184. // 检查 indices[i] 是否已经在 indices[0..j-1] 中出现过
  185. for (unsigned int k = 0; k < j; k++)
  186. {
  187. if (indices[i] == indices[k])
  188. {
  189. is_duplicate = true;
  190. break;
  191. }
  192. }
  193. // 如果不是重复元素,则加入去重后的数组
  194. if (!is_duplicate)
  195. {
  196. indices[j++] = indices[i];
  197. }
  198. }
  199. *index_count = j; // 更新数组长度
  200. }
  201. bool line_vacuate_c(const studio_line_c *line, const int max_points, const double epsilon, studio_line_c *vacuate_line)
  202. {
  203. // 初始化状态变量
  204. bool status = false;
  205. // 如果输入的线段为空,则打印错误信息并返回false
  206. if (line->size == 0)
  207. {
  208. printf("line is empty\n");
  209. return false;
  210. }
  211. // 如果输入的线段点数小于等于最大点数,则直接将线段点添加到vacuate_line中,并返回true
  212. if (line->size <= max_points)
  213. {
  214. for (size_t i = 0; i < line->size; ++i)
  215. {
  216. studio_line_c_add_point(vacuate_line, line->data[i]);
  217. }
  218. status = true;
  219. return status;
  220. }
  221. // 分配内存空间存储线段点的索引
  222. unsigned int *indices = (unsigned int *)malloc(line->size * sizeof(unsigned int));
  223. if (!indices)
  224. {
  225. // 内存分配失败处理
  226. return false;
  227. }
  228. unsigned int index_count = 0;
  229. const unsigned int max_indices = line->size;
  230. double t_epsilon = epsilon;
  231. // 循环执行Douglas-Peucker算法,直到索引点数小于等于最大点数
  232. while (1)
  233. {
  234. index_count = 0;
  235. // douglas_peucker_c(line, 0, line->size - 1, t_epsilon, indices, &index_count);
  236. douglas_peucker_c(line, 0, line->size - 1, t_epsilon, indices, &index_count, max_indices);
  237. // 将indices 中的数据去重 保持顺序
  238. remove_duplicates(indices, &index_count);
  239. if (index_count <= (unsigned int)max_points)
  240. {
  241. break;
  242. }
  243. t_epsilon *= 1.1;
  244. }
  245. // 将索引点添加到vacuate_line中
  246. for (unsigned int i = 0; i < index_count; ++i)
  247. {
  248. studio_line_c_add_point(vacuate_line, line->data[indices[i]]);
  249. }
  250. // 释放内存空间
  251. free(indices);
  252. status = true;
  253. return status;
  254. }
  255. bool line_vacuate_gcs_c(const studio_line_c *line, const int max_points, const double epsilon, studio_line_c *vacuate_line)
  256. {
  257. bool status = false;
  258. if (!line || !vacuate_line || line->size <= 1) // 添加空指针和长度校验
  259. {
  260. printf("line or vacuate_line is null or line size <= 1");
  261. return status;
  262. }
  263. // 经纬度转高斯克吕格投影
  264. studio_line_c gauss_line = studio_line_c_init();
  265. // double central = ((int) (line->data[0].x) / 3) * 3;
  266. double central = floor((line->data[0].x + 1.5) / 3.0) * 3.0;
  267. for (unsigned int i = 0; i < line->size; i++)
  268. {
  269. double gx, gy;
  270. lonlat_to_gauss(central, line->data[i].x, line->data[i].y, &gx, &gy);
  271. studio_point_c point = studio_point_init(gx, gy);
  272. studio_line_c_add_point(&gauss_line, point);
  273. }
  274. studio_line_c vac_gauss_line = studio_line_c_init();
  275. bool res = line_vacuate_c(&gauss_line, max_points, epsilon, &vac_gauss_line);
  276. if (!res)
  277. {
  278. printf("Failed to simplify line.");
  279. return status;
  280. }
  281. studio_line_c_destroy(&gauss_line);
  282. // 高斯克吕格转经纬度
  283. for (unsigned int i = 0; i < vac_gauss_line.size; i++)
  284. {
  285. double lon, lat;
  286. gauss_to_lonlat(central, vac_gauss_line.data[i].x, vac_gauss_line.data[i].y, &lon, &lat);
  287. studio_point_c point = studio_point_init(lon, lat);
  288. studio_line_c_add_point(vacuate_line, point);
  289. }
  290. studio_line_c_destroy(&vac_gauss_line);
  291. status = true;
  292. return status;
  293. }
  294. bool remove_outliers_c(const studio_line_c *line, double distance, studio_line_c *outliers_line)
  295. {
  296. bool status = false;
  297. if (!line || !outliers_line || line->size <= 1) // 添加空指针和长度校验
  298. {
  299. printf("line or outliers_line is null or line size <= 1");
  300. return status;
  301. }
  302. double dist_square = distance * distance;
  303. // 经纬度转高斯克吕格投影
  304. studio_line_c gauss_line = studio_line_c_init();
  305. // double central = ((int) (line->data[0].x) / 3) * 3;
  306. double central = floor((line->data[0].x + 1.5) / 3.0) * 3.0;
  307. for (unsigned int i = 0; i < line->size; i++)
  308. {
  309. double gx, gy;
  310. lonlat_to_gauss(central, line->data[i].x, line->data[i].y, &gx, &gy);
  311. studio_point_c point = studio_point_init(gx, gy);
  312. studio_line_c_add_point(&gauss_line, point);
  313. }
  314. // 离群点检测 ------------------------------------------------
  315. if (gauss_line.size <= 1)
  316. {
  317. printf("gauss_line size <= 1");
  318. return status;
  319. }
  320. studio_line_c gs_filtered_line = studio_line_c_init(); // 新建过滤后的线段
  321. studio_line_c_add_point(&gs_filtered_line, gauss_line.data[0]); // 保留第一个点
  322. for (unsigned int i = 1; i < gauss_line.size; i++) // 遍历相邻点对
  323. {
  324. double d_sq = distance_squared_c(&gauss_line.data[i - 1], &gauss_line.data[i]);
  325. if (d_sq <= dist_square)
  326. {
  327. studio_line_c_add_point(&gs_filtered_line, gauss_line.data[i]);
  328. }
  329. else
  330. {
  331. int a = 0;
  332. }
  333. }
  334. studio_line_c_destroy(&gauss_line); // 释放原始数据的高斯投影
  335. // 高斯克吕格转经纬度
  336. for (unsigned int i = 0; i < gs_filtered_line.size; i++)
  337. {
  338. double lon, lat;
  339. gauss_to_lonlat(central, gs_filtered_line.data[i].x, gs_filtered_line.data[i].y, &lon, &lat);
  340. studio_point_c point = studio_point_init(lon, lat);
  341. studio_line_c_add_point(outliers_line, point);
  342. }
  343. studio_line_c_destroy(&gs_filtered_line); // 释放移除离群点后的高斯投影
  344. status = true;
  345. return status;
  346. }