#include "cdrapp.h" // 扩展边界框 void expand_bounding_boxes(std::vector& boxes, double exp) { for (auto& box : boxes) { // 扩展宽度和高度 box.w += 2 * exp; // 左右各扩展 box.h += 2 * exp; // 上下各扩展 // 调整左下角坐标 box.x -= exp; // 向左扩展 box.y -= exp; // 向下扩展 } } double get_bounding_box_area(BoundingBox box) { return box.w * box.h; } // 自定义比较函数,按 BoundingBox 的面积大小进行排序 bool compare_bounding_boxes(const std::pair &a, const std::pair &b) { return get_bounding_box_area(a.second) > get_bounding_box_area(b.second); } // 查找父节点 int find(std::vector& parent, int x) { if (parent[x] != x) { parent[x] = find(parent, parent[x]); } return parent[x]; } // 合并两个集合 void unionSet(std::vector& parent, int x, int y) { int xroot = find(parent, x); int yroot = find(parent, y); parent[xroot] = yroot; } // 检查两个矩形是否重叠 bool isOverlapped(const BoundingBox &a, const BoundingBox &b) { 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; } // 函数使用AABB(Axis-Aligned Bounding Box)碰撞检测 bool BBox_DrawRectangle(corel *cdr, double exp) { BoundingBox box; auto sr = cdr->ActiveSelectionRange; // 获得选择范围 auto al = cdr->ActiveVirtualLayer; // 虚拟物件虚拟层 if (!sr || !al) return false; BeginOpt(cdr); auto srs = cdr->CreateShapeRange(); // CorelDRAW Shapes 物件 Item 编号从1开始 for (auto i = 0; i != sr->Count; i++) { sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box); // 获得Shapes的BoundingBox,赋值到box if (fabs(exp) > 0.02 ) { box.w += 2 * exp; box.h += 2 * exp; box.x -= exp; box.y -= exp; } auto s = al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC); // 使用BoundingBox box 创建一个矩形 s->Outline->Color->RGBAssign(0, 255, 0); srs->Add(s); } cdr->ActiveDocument->LogCreateShapeRange(srs); // 虚拟物件添加到文档中 srs->CreateSelection(); // sprintf(infobuf, "提示: 标记画框数量: %d 个\n容差值请使用小键盘输入", srs->Count); sprintf(infobuf, "Tip: Number of marked frames: %d\nPlease use the numeric keypad to enter the tolerance value", srs->Count); EndOpt(cdr); return true; } bool AutoMakeSelection(corel *cdr) { auto sr = cdr->ActiveSelectionRange; if (0 == sr->Count) { auto all = cdr->ActiveDocument->ActivePage->Shapes->All(); all->CreateSelection(); } return true; } // 快速分组重叠的区域, 使用算法"Union-Find" 算法。这个算法可以有效地处理这种并集问题。 // 算法的时间复杂度为 O(n^2),其中 n 是矩形的数量。如果矩形数量较多,可以考虑使用更高效的算法, // 例如使用四叉树(Quadtree)或者区间树(Interval Tree)等数据结构来加速计算。 bool Box_AutoGroup(corel *cdr, double exp) { BoundingBox box; auto sr = cdr->ActiveSelectionRange; // 获得选择范围 auto al = cdr->ActiveLayer; // 获得当前层 if (!sr || !al) return false; auto start = std::chrono::high_resolution_clock::now(); // 开始时间 BeginOpt(cdr); std::vector boxes; std::vector parent; // CorelDRAW Shapes 物件 Item 编号从1开始 for (auto i = 0; i != sr->Count; i++) { sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box); boxes.push_back(box); parent.push_back(i); } // 扩展边界框,或者收缩边界框 if (fabs(exp) > 0.02 ) { expand_bounding_boxes(boxes, exp); } // 实现 Union-Find 算法来合并重叠的区域 for (int i = 0; i < boxes.size(); i++) { for (int j = i + 1; j < boxes.size(); j++) { if (isOverlapped(boxes[i], boxes[j])) { unionSet(parent, i, j); } } } double runtime[2] = {0,0}; auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration duration = end - start; runtime[0] = duration.count(); // 输出分组结果到文件 // std::ofstream output_file("D:\\group.txt"); // if (output_file.is_open()) { // std::map> groups; // for (int i = 0; i < parent.size(); i++) { // int root = find(parent, i); // groups[root].push_back(i + 1); // CorelDRAW Shapes 物件 Item 编号从1开始 // } // for (const auto& group : groups) { // output_file << "Group: "; // for (int index : group.second) { // output_file << index << " "; // } // output_file << std::endl; // } // auto end = std::chrono::high_resolution_clock::now(); // 结束时间 // // 计算持续时间 // std::chrono::duration duration = end - start; // output_file << "Execution time: " << duration.count() << " seconds\n"; // output_file.close(); // } // 输出分组结果 std::map> groups; for (int i = 0; i < parent.size(); i++) { int root = find(parent, i); groups[root].push_back(i + 1); // CorelDRAW Shapes 物件 Item 编号从1开始 } auto srgp = cdr->CreateShapeRange(); auto srs = cdr->CreateShapeRange(); cdr->ActiveDocument->ClearSelection(); // 原来 没有取消选择 最初速度 // Execution time: 63.0305 seconds // srgp->GET_BOUNDING_BOX(box); // al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC); // 使用边界 创建一个矩形 // box边界 转左上和右下坐标 box.x, box.y + box.h, box.x + box.w, box.y // auto sh = cdr->ActivePage->SelectShapesFromRectangle(box.x, box.y + box.h, box.x + box.w, box.y, false); // sh->Group(); // 使用 SelectShapesFromRectangle 框选的形状进行群组 // Execution time: 2.44753 seconds // cdr->ActiveDocument->ClearSelection(); // 使用取消选择 // Execution time: 1.7432 seconds // srgp->CreateSelection(); // cdr->ActiveSelectionRange->Group(); // Execution time: 1.87662 seconds // 分组分别进行群组 for (const auto& group : groups) { for (int index : group.second) srgp->Add(sr->Shapes->Item[index]); if(sr->Count >1) srs->Add(srgp->Group()); else srs->AddRange(srgp); srgp->RemoveAll(); } srs->CreateSelection(); // 计算持续时间 duration = std::chrono::high_resolution_clock::now() - start; runtime[1] = duration.count(); // sprintf(infobuf, "选择物件: %d 个, 分组: %.2f秒\n总共群组: %d 组, 总时间: %.2f秒", sr->Count, runtime[0] + 0.01, srs->Count, runtime[1] + 0.02); 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); EndOpt(cdr); return true; } // 按矩形框范围分组,供其他功能调用 bool BoxGrouping(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs, double exp ) { BoundingBox box; auto al = cdr->ActiveLayer; // 获得当前层 if (!sr || !al) return false; std::vector boxes; std::vector parent; // CorelDRAW Shapes 物件 Item 编号从1开始 for (auto i = 0; i != sr->Count; i++) { sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box); boxes.push_back(box); parent.push_back(i); } // 扩展边界框,或者收缩边界框 if (fabs(exp) > 0.02 ) { expand_bounding_boxes(boxes, exp); } // 实现 Union-Find 算法来合并重叠的区域 for (int i = 0; i < boxes.size(); i++) { for (int j = i + 1; j < boxes.size(); j++) { if (isOverlapped(boxes[i], boxes[j])) { unionSet(parent, i, j); } } } // 输出分组结果 std::map> groups; for (int i = 0; i < parent.size(); i++) { int root = find(parent, i); groups[root].push_back(i + 1); } auto srgp = cdr->CreateShapeRange(); // 分组分别进行群组 for (const auto& group : groups) { for (int index : group.second) srgp->Add(sr->Shapes->Item[index]); if(sr->Count >1) srs->Add(srgp->Group()); else{ srs->AddRange(srgp); } srgp->RemoveAll(); } return true; }