boxAutoGroup.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "cdrapp.h"
  2. #include <algorithm>
  3. #include <map>
  4. #include <vector>
  5. #include <iostream>
  6. #include <fstream>
  7. #include <chrono>
  8. #include <math.h>
  9. #define GET_BOUNDING_BOX(box) \
  10. GetBoundingBox(&(box).x, &(box).y, &(box).w, &(box).h, false)
  11. #define ZERO_4PC 0, 0, 0, 0
  12. typedef struct {
  13. double x; // 左下角 x 坐标
  14. double y; // 左下角 y 坐标
  15. double w; // 宽度
  16. double h; // 高度
  17. } BoundingBox;
  18. // 扩展边界框
  19. void expand_bounding_boxes(std::vector<BoundingBox>& boxes, double exp) {
  20. for (auto& box : boxes) {
  21. // 扩展宽度和高度
  22. box.w += 2 * exp; // 左右各扩展
  23. box.h += 2 * exp; // 上下各扩展
  24. // 调整左下角坐标
  25. box.x -= exp; // 向左扩展
  26. box.y -= exp; // 向下扩展
  27. }
  28. }
  29. double get_bounding_box_area(BoundingBox box) { return box.w * box.h; }
  30. // 自定义比较函数,按 BoundingBox 的面积大小进行排序
  31. bool compare_bounding_boxes(const std::pair<int, BoundingBox> &a,
  32. const std::pair<int, BoundingBox> &b) {
  33. return get_bounding_box_area(a.second) > get_bounding_box_area(b.second);
  34. }
  35. // 查找父节点
  36. int find(std::vector<int>& parent, int x) {
  37. if (parent[x] != x) {
  38. parent[x] = find(parent, parent[x]);
  39. }
  40. return parent[x];
  41. }
  42. // 合并两个集合
  43. void unionSet(std::vector<int>& parent, int x, int y) {
  44. int xroot = find(parent, x);
  45. int yroot = find(parent, y);
  46. parent[xroot] = yroot;
  47. }
  48. // 检查两个矩形是否重叠
  49. bool isOverlapped(const BoundingBox &a, const BoundingBox &b) {
  50. return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
  51. } // 函数使用AABB(Axis-Aligned Bounding Box)碰撞检测
  52. bool BBox_DrawRectangle(corel *cdr, double exp) {
  53. BoundingBox box;
  54. auto sr = cdr->ActiveSelectionRange; // 获得选择范围
  55. auto al = cdr->ActiveLayer; // 获得当前层
  56. if (!sr || !al) return false;
  57. BeginOpt(cdr);
  58. auto srs = cdr->CreateShapeRange();
  59. // CorelDRAW Shapes 物件 Item 编号从1开始
  60. for (auto i = 0; i != sr->Count; i++) {
  61. sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box); // 获得Shapes的BoundingBox,赋值到box
  62. if (fabs(exp) > 0.02 ) { box.w += 2 * exp; box.h += 2 * exp; box.x -= exp; box.y -= exp; }
  63. auto s = al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC); // 使用BoundingBox box 创建一个矩形
  64. s->Outline->Color->RGBAssign(0, 255, 0);
  65. srs->Add(s);
  66. }
  67. srs->CreateSelection();
  68. EndOpt(cdr);
  69. return true;
  70. }
  71. bool AutoMakeSelection(corel *cdr) {
  72. auto sr = cdr->ActiveSelectionRange;
  73. if (0 == sr->Count) {
  74. auto all = cdr->ActiveDocument->ActivePage->Shapes->All();
  75. all->CreateSelection();
  76. }
  77. return true;
  78. }
  79. // 快速分组重叠的区域, 使用算法"Union-Find" 算法。这个算法可以有效地处理这种并集问题。
  80. // 算法的时间复杂度为 O(n^2),其中 n 是矩形的数量。如果矩形数量较多,可以考虑使用更高效的算法,
  81. // 例如使用四叉树(Quadtree)或者区间树(Interval Tree)等数据结构来加速计算。
  82. bool Box_AutoGroup(corel *cdr, double exp) {
  83. BoundingBox box;
  84. auto sr = cdr->ActiveSelectionRange; // 获得选择范围
  85. auto al = cdr->ActiveLayer; // 获得当前层
  86. if (!sr || !al) return false;
  87. auto start = std::chrono::high_resolution_clock::now(); // 开始时间
  88. BeginOpt(cdr);
  89. std::vector<BoundingBox> boxes;
  90. std::vector<int> parent;
  91. // CorelDRAW Shapes 物件 Item 编号从1开始
  92. for (auto i = 0; i != sr->Count; i++) {
  93. sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box);
  94. boxes.push_back(box);
  95. parent.push_back(i);
  96. }
  97. // 扩展边界框,或者收缩边界框
  98. if (fabs(exp) > 0.02 ) {
  99. expand_bounding_boxes(boxes, exp);
  100. }
  101. // 实现 Union-Find 算法来合并重叠的区域
  102. for (int i = 0; i < boxes.size(); i++) {
  103. for (int j = i + 1; j < boxes.size(); j++) {
  104. if (isOverlapped(boxes[i], boxes[j])) {
  105. unionSet(parent, i, j);
  106. }
  107. }
  108. }
  109. // 输出分组结果到文件
  110. std::ofstream output_file("D:\\group.txt");
  111. if (output_file.is_open()) {
  112. std::map<int, std::vector<int>> groups;
  113. for (int i = 0; i < parent.size(); i++) {
  114. int root = find(parent, i);
  115. groups[root].push_back(i + 1); // CorelDRAW Shapes 物件 Item 编号从1开始
  116. }
  117. for (const auto& group : groups) {
  118. output_file << "Group: ";
  119. for (int index : group.second) {
  120. output_file << index << " ";
  121. }
  122. output_file << std::endl;
  123. }
  124. auto end = std::chrono::high_resolution_clock::now(); // 结束时间
  125. // 计算持续时间
  126. std::chrono::duration<double> duration = end - start;
  127. output_file << "Execution time: " << duration.count() << " seconds\n";
  128. output_file.close();
  129. }
  130. // 输出分组结果
  131. std::map<int, std::vector<int>> groups;
  132. for (int i = 0; i < parent.size(); i++) {
  133. int root = find(parent, i);
  134. groups[root].push_back(i + 1); // CorelDRAW Shapes 物件 Item 编号从1开始
  135. }
  136. auto srgp = cdr->CreateShapeRange();
  137. auto srs = cdr->CreateShapeRange();
  138. cdr->ActiveDocument->ClearSelection();
  139. // 原来 没有取消选择 最初速度
  140. // Execution time: 63.0305 seconds
  141. // srgp->GET_BOUNDING_BOX(box);
  142. // al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC); // 使用边界 创建一个矩形
  143. // box边界 转左上和右下坐标 box.x, box.y + box.h, box.x + box.w, box.y
  144. // auto sh = cdr->ActivePage->SelectShapesFromRectangle(box.x, box.y + box.h, box.x + box.w, box.y, false);
  145. // sh->Group();
  146. // 使用 SelectShapesFromRectangle 框选的形状进行群组
  147. // Execution time: 2.44753 seconds
  148. // cdr->ActiveDocument->ClearSelection(); // 使用取消选择
  149. // Execution time: 1.7432 seconds
  150. // srgp->CreateSelection();
  151. // cdr->ActiveSelectionRange->Group();
  152. // Execution time: 1.87662 seconds
  153. // 分组分别进行群组
  154. for (const auto& group : groups) {
  155. for (int index : group.second)
  156. srgp->Add(sr->Shapes->Item[index]);
  157. if(sr->Count >1)
  158. srs->Add(srgp->Group());
  159. else
  160. srs->AddRange(srgp);
  161. srgp->RemoveAll();
  162. }
  163. srs->CreateSelection();
  164. EndOpt(cdr);
  165. return true;
  166. }