studio_geo_algo_c.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. void remove_duplicates(unsigned int **indices, unsigned int *size) {
  77. if (*size == 0) return;
  78. // 临时数组用于存储去重后的数据
  79. unsigned int *unique_indices = (unsigned int *)malloc(*size * sizeof(unsigned int));
  80. unsigned int unique_count = 0;
  81. for (unsigned int i = 0; i < *size; i++) {
  82. unsigned int is_duplicate = 0;
  83. // 检查当前元素是否已经在 unique_indices 中
  84. for (unsigned int j = 0; j < unique_count; j++) {
  85. if ((*indices)[i] == unique_indices[j]) {
  86. is_duplicate = 1;
  87. break;
  88. }
  89. }
  90. // 如果没有重复,添加到 unique_indices
  91. if (!is_duplicate) {
  92. unique_indices[unique_count] = (*indices)[i];
  93. unique_count++;
  94. }
  95. }
  96. // 释放原有的 indices
  97. free(*indices);
  98. // 更新 indices 指针和大小
  99. *indices = unique_indices;
  100. *size = unique_count;
  101. }
  102. bool line_vacuate_c(const studio_line_c *line, const int max_points, const double epsilon, studio_line_c *vacuate_line)
  103. {
  104. // 初始化状态变量
  105. bool status = false;
  106. // 如果输入的线段为空,则打印错误信息并返回false
  107. if (line->size == 0)
  108. {
  109. printf("line is empty\n");
  110. return false;
  111. }
  112. // 如果输入的线段点数小于等于最大点数,则直接将线段点添加到vacuate_line中,并返回true
  113. if (line->size <= max_points)
  114. {
  115. for (size_t i = 0; i < line->size; ++i)
  116. {
  117. studio_line_c_add_point(vacuate_line, line->data[i]);
  118. }
  119. status = true;
  120. return status;
  121. }
  122. // 分配内存空间存储线段点的索引
  123. unsigned int *indices = (unsigned int *)malloc(line->size * sizeof(unsigned int));
  124. unsigned int index_count = 0;
  125. double t_epsilon = epsilon;
  126. // 循环执行Douglas-Peucker算法,直到索引点数小于等于最大点数
  127. while (1)
  128. {
  129. index_count = 0;
  130. douglas_peucker_c(line, 0, line->size - 1, t_epsilon, indices, &index_count);
  131. // 将indices 中的数据去重
  132. remove_duplicates(&indices, &index_count);
  133. if (index_count <= (unsigned int)max_points)
  134. {
  135. break;
  136. }
  137. t_epsilon *= 1.1;
  138. }
  139. // 将索引点添加到vacuate_line中
  140. for (unsigned int i = 0; i < index_count; ++i)
  141. {
  142. studio_line_c_add_point(vacuate_line, line->data[indices[i]]);
  143. }
  144. // 释放内存空间
  145. free(indices);
  146. status = true;
  147. return status;
  148. }