studio_geo_algo_c.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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. double distance_squared(const studio_point_c *p1, const studio_point_c *p2)
  13. {
  14. const double dx = p1->x - p2->x;
  15. const double dy = p1->y - p2->y;
  16. return dx * dx + dy * dy;
  17. }
  18. double point_line_dist_square_c(const studio_point_c *p, const studio_point_c *start, const studio_point_c *end)
  19. {
  20. double A = p->x - start->x;
  21. double B = p->y - start->y;
  22. double C = end->x - start->x;
  23. double D = end->y - start->y;
  24. double dot = A * C + B * D;
  25. double len_sq = C * C + D * D;
  26. double param = len_sq == 0 ? -1 : dot / len_sq;
  27. double xx, yy;
  28. if (param < 0)
  29. {
  30. xx = start->x;
  31. yy = start->y;
  32. } else if (param > 1)
  33. {
  34. xx = end->x;
  35. yy = end->y;
  36. } else
  37. {
  38. xx = start->x + param * C;
  39. yy = start->y + param * D;
  40. }
  41. double dist_square = (xx - p->x) * (xx - p->x) + (yy - p->y) * (yy - p->y);
  42. return dist_square;
  43. }
  44. // Douglas-Peucker算法,用于简化多边形或曲线
  45. void douglas_peucker_c(const studio_line_c *points, size_t start, size_t end, double epsilon, unsigned int *indices,
  46. unsigned int *index_count)
  47. {
  48. // 计算最大距离
  49. double max_dist = 0;
  50. size_t index = start;
  51. double epsilon_square = epsilon * epsilon;
  52. // 遍历从start+1到end-1的点
  53. for (size_t i = start + 1; i < end; ++i)
  54. {
  55. // 计算点到线段的距离的平方
  56. double dist_square = point_line_dist_square_c(&points->data[i], &points->data[start], &points->data[end]);
  57. // 如果距离大于最大距离,则更新最大距离和索引
  58. if (dist_square > max_dist)
  59. {
  60. index = i;
  61. max_dist = dist_square;
  62. }
  63. }
  64. // 如果最大距离大于epsilon的平方,并且索引不是start和end,则递归调用Douglas-Peucker算法
  65. if (max_dist > epsilon_square && index != start && index != end)
  66. {
  67. douglas_peucker_c(points, start, index, epsilon, indices, index_count);
  68. douglas_peucker_c(points, index, end, epsilon, indices, index_count);
  69. }
  70. // 否则,将start和end的索引添加到indices数组中
  71. else
  72. {
  73. indices[*index_count] = start;
  74. (*index_count)++;
  75. if (start != end)
  76. {
  77. indices[*index_count] = end;
  78. (*index_count)++;
  79. }
  80. }
  81. }
  82. unsigned int hash(unsigned int value, unsigned int size)
  83. {
  84. return value % size;
  85. }
  86. void remove_duplicates(unsigned int **indices, unsigned int *size)
  87. {
  88. if (*size == 0)
  89. {
  90. return;
  91. }
  92. unsigned int *unique_indices = (unsigned int *) malloc(*size * sizeof(unsigned int));
  93. unsigned int unique_count = 0;
  94. // 创建一个哈希表
  95. unsigned int hash_table_size = *size * 4; // 哈希表大小可以稍微增大以减少冲突 这个可能有问题
  96. bool *hash_table = (bool *) malloc(hash_table_size * sizeof(bool));
  97. for (unsigned int i = 0; i < hash_table_size; i++)
  98. {
  99. hash_table[i] = false; // 初始化哈希表
  100. }
  101. for (unsigned int i = 0; i < *size; i++)
  102. {
  103. unsigned int current_value = (*indices)[i];
  104. unsigned int hash_index = hash(current_value, hash_table_size);
  105. // 检查该元素是否已经在哈希表中
  106. if (!hash_table[hash_index])
  107. {
  108. hash_table[hash_index] = true;
  109. unique_indices[unique_count++] = current_value;
  110. }
  111. }
  112. // 释放原有的 indices 和哈希表
  113. free(*indices);
  114. free(hash_table);
  115. // 更新 indices 指针和大小
  116. *indices = unique_indices;
  117. *size = unique_count;
  118. }
  119. bool line_vacuate_c(const studio_line_c *line, const int max_points, const double epsilon, studio_line_c *vacuate_line)
  120. {
  121. // 初始化状态变量
  122. bool status = false;
  123. // 如果输入的线段为空,则打印错误信息并返回false
  124. if (line->size == 0)
  125. {
  126. printf("line is empty\n");
  127. return false;
  128. }
  129. // 如果输入的线段点数小于等于最大点数,则直接将线段点添加到vacuate_line中,并返回true
  130. if (line->size <= max_points)
  131. {
  132. for (size_t i = 0; i < line->size; ++i)
  133. {
  134. studio_line_c_add_point(vacuate_line, line->data[i]);
  135. }
  136. status = true;
  137. return status;
  138. }
  139. // 分配内存空间存储线段点的索引
  140. unsigned int *indices = (unsigned int *) malloc(line->size * sizeof(unsigned int));
  141. unsigned int index_count = 0;
  142. double t_epsilon = epsilon;
  143. // 循环执行Douglas-Peucker算法,直到索引点数小于等于最大点数
  144. while (1)
  145. {
  146. index_count = 0;
  147. douglas_peucker_c(line, 0, line->size - 1, t_epsilon, indices, &index_count);
  148. // 将indices 中的数据去重
  149. remove_duplicates(&indices, &index_count);
  150. if (index_count <= (unsigned int) max_points)
  151. {
  152. break;
  153. }
  154. t_epsilon *= 1.1;
  155. }
  156. // 将索引点添加到vacuate_line中
  157. for (unsigned int i = 0; i < index_count; ++i)
  158. {
  159. studio_line_c_add_point(vacuate_line, line->data[indices[i]]);
  160. }
  161. // 释放内存空间
  162. free(indices);
  163. status = true;
  164. return status;
  165. }
  166. bool remove_outliers_c(const studio_line_c *line, double distance, studio_line_c *outliers_line)
  167. {
  168. bool status = false;
  169. if (!line || !outliers_line || line->size <= 1) // 添加空指针和长度校验
  170. {
  171. printf("line or outliers_line is null or line size <= 1");
  172. return status;
  173. }
  174. double dist_square = distance * distance;
  175. // 经纬度转高斯克吕格投影
  176. studio_line_c gauss_line = studio_line_c_init();
  177. double central = (int) (line->data[0].x) / 3 * 3;
  178. for (unsigned int i = 0; i < line->size; i++)
  179. {
  180. double gx, gy;
  181. lonlat_to_gauss(central, line->data[i].x, line->data[i].y, &gx, &gy);
  182. studio_point_c point = studio_point_init(gx, gy);
  183. studio_line_c_add_point(&gauss_line, point);
  184. }
  185. // 离群点检测 ------------------------------------------------
  186. if (gauss_line.size<= 1)
  187. {
  188. printf("gauss_line size <= 1");
  189. return status;
  190. }
  191. studio_line_c gs_filtered_line = studio_line_c_init(); // 新建过滤后的线段
  192. studio_line_c_add_point(&gs_filtered_line, gauss_line.data[0]); // 保留第一个点
  193. for (unsigned int i = 1; i < gauss_line.size; i++) // 遍历相邻点对
  194. {
  195. double d_sq = distance_squared(&gauss_line.data[i - 1], &gauss_line.data[i]);
  196. if (d_sq <= dist_square)
  197. {
  198. studio_line_c_add_point(&gs_filtered_line, gauss_line.data[i]);
  199. }
  200. else
  201. {
  202. int a=0;
  203. }
  204. }
  205. studio_line_c_destroy(&gauss_line); // 释放原始数据的高斯投影
  206. // 高斯克吕格转经纬度
  207. for (unsigned int i = 0; i < gs_filtered_line.size; i++)
  208. {
  209. double lon, lat;
  210. gauss_to_lonlat(central, gs_filtered_line.data[i].x, gs_filtered_line.data[i].y, &lon, &lat);
  211. studio_point_c point = studio_point_init(lon, lat);
  212. studio_line_c_add_point(outliers_line, point);
  213. }
  214. studio_line_c_destroy(&gs_filtered_line); // 释放移除离群点后的高斯投影
  215. status = true;
  216. return status;
  217. }