studio_geo_algo_c.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. double point_line_dist_square_c(const studio_point_c *p, const studio_point_c *start, const studio_point_c *end)
  12. {
  13. double A = p->x - start->x;
  14. double B = p->y - start->y;
  15. double C = end->x - start->x;
  16. double D = end->y - start->y;
  17. double dot = A * C + B * D;
  18. double len_sq = C * C + D * D;
  19. double param = len_sq == 0 ? -1 : dot / len_sq;
  20. double xx, yy;
  21. if (param < 0)
  22. {
  23. xx = start->x;
  24. yy = start->y;
  25. }
  26. else if (param > 1)
  27. {
  28. xx = end->x;
  29. yy = end->y;
  30. }
  31. else
  32. {
  33. xx = start->x + param * C;
  34. yy = start->y + param * D;
  35. }
  36. double dist_square = (xx - p->x) * (xx - p->x) + (yy - p->y) * (yy - p->y);
  37. return dist_square;
  38. }
  39. // Douglas-Peucker算法,用于简化多边形或曲线
  40. void douglas_peucker_c(const studio_line_c *points, size_t start, size_t end, double epsilon, unsigned int *indices, unsigned int *index_count)
  41. {
  42. // 计算最大距离
  43. double max_dist = 0;
  44. size_t index = start;
  45. double epsilon_square = epsilon * epsilon;
  46. // 遍历从start+1到end-1的点
  47. for (size_t i = start + 1; i < end; ++i)
  48. {
  49. // 计算点到线段的距离的平方
  50. double dist_square = point_line_dist_square_c(&points->data[i], &points->data[start], &points->data[end]);
  51. // 如果距离大于最大距离,则更新最大距离和索引
  52. if (dist_square > max_dist)
  53. {
  54. index = i;
  55. max_dist = dist_square;
  56. }
  57. }
  58. // 如果最大距离大于epsilon的平方,并且索引不是start和end,则递归调用Douglas-Peucker算法
  59. if (max_dist > epsilon_square && index != start && index != end)
  60. {
  61. douglas_peucker_c(points, start, index, epsilon, indices, index_count);
  62. douglas_peucker_c(points, index, end, epsilon, indices, index_count);
  63. }
  64. // 否则,将start和end的索引添加到indices数组中
  65. else
  66. {
  67. indices[*index_count] = start;
  68. (*index_count)++;
  69. if (start != end)
  70. {
  71. indices[*index_count] = end;
  72. (*index_count)++;
  73. }
  74. }
  75. }
  76. unsigned int hash(unsigned int value, unsigned int size)
  77. {
  78. return value % size;
  79. }
  80. void remove_duplicates(unsigned int **indices, unsigned int *size)
  81. {
  82. if (*size == 0)
  83. {
  84. return;
  85. }
  86. unsigned int *unique_indices = (unsigned int *)malloc(*size * sizeof(unsigned int));
  87. unsigned int unique_count = 0;
  88. // 创建一个哈希表
  89. unsigned int hash_table_size = *size * 4; // 哈希表大小可以稍微增大以减少冲突 这个可能有问题
  90. bool *hash_table = (bool *)malloc(hash_table_size * sizeof(bool));
  91. for (unsigned int i = 0; i < hash_table_size; i++)
  92. {
  93. hash_table[i] = false; // 初始化哈希表
  94. }
  95. for (unsigned int i = 0; i < *size; i++)
  96. {
  97. unsigned int current_value = (*indices)[i];
  98. unsigned int hash_index = hash(current_value, hash_table_size);
  99. // 检查该元素是否已经在哈希表中
  100. if (!hash_table[hash_index])
  101. {
  102. hash_table[hash_index] = true;
  103. unique_indices[unique_count++] = current_value;
  104. }
  105. }
  106. // 释放原有的 indices 和哈希表
  107. free(*indices);
  108. free(hash_table);
  109. // 更新 indices 指针和大小
  110. *indices = unique_indices;
  111. *size = unique_count;
  112. }
  113. bool line_vacuate_c(const studio_line_c *line, const int max_points, const double epsilon, studio_line_c *vacuate_line)
  114. {
  115. // 初始化状态变量
  116. bool status = false;
  117. // 如果输入的线段为空,则打印错误信息并返回false
  118. if (line->size == 0)
  119. {
  120. printf("line is empty\n");
  121. return false;
  122. }
  123. // 如果输入的线段点数小于等于最大点数,则直接将线段点添加到vacuate_line中,并返回true
  124. if (line->size <= max_points)
  125. {
  126. for (size_t i = 0; i < line->size; ++i)
  127. {
  128. studio_line_c_add_point(vacuate_line, line->data[i]);
  129. }
  130. status = true;
  131. return status;
  132. }
  133. // 分配内存空间存储线段点的索引
  134. unsigned int *indices = (unsigned int *)malloc(line->size * sizeof(unsigned int));
  135. unsigned int index_count = 0;
  136. double t_epsilon = epsilon;
  137. // 循环执行Douglas-Peucker算法,直到索引点数小于等于最大点数
  138. while (1)
  139. {
  140. index_count = 0;
  141. douglas_peucker_c(line, 0, line->size - 1, t_epsilon, indices, &index_count);
  142. // 将indices 中的数据去重
  143. remove_duplicates(&indices, &index_count);
  144. if (index_count <= (unsigned int)max_points)
  145. {
  146. break;
  147. }
  148. t_epsilon *= 1.1;
  149. }
  150. // 将索引点添加到vacuate_line中
  151. for (unsigned int i = 0; i < index_count; ++i)
  152. {
  153. studio_line_c_add_point(vacuate_line, line->data[indices[i]]);
  154. }
  155. // 释放内存空间
  156. free(indices);
  157. status = true;
  158. return status;
  159. }