boxAutoGroup.cpp 8.1 KB

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