2 Commits 99d26d4abd ... f6d0cb6f0d

Author SHA1 Message Date
  Hongwenjun f6d0cb6f0d 调用矩形分组,分布执行异形群组 大幅提高速度 2 weeks ago
  Hongwenjun a5cb0fbc9a 异形群组,添加文字处理情况 2 weeks ago

+ 63 - 22
09_BoundaryGroup/BoundaryGroup.cpp

@@ -1,16 +1,7 @@
 #include "cdrapp.h"
+#include <cerrno>
+#include <cmath>
 
-#define GET_BOUNDING_BOX(box)                                                  \
-  GetBoundingBox(&(box).x, &(box).y, &(box).w, &(box).h, false)
-
-#define ZERO_4PC 0, 0, 0, 0
-
-typedef struct {
-  double x; // 左下角 x 坐标
-  double y; // 左下角 y 坐标
-  double w; // 宽度
-  double h; // 高度
-} BoundingBox;
 bool isDPCurve(IVGShapePtr s) {
   auto dpc = (s->Type == cdrRectangleShape) || (s->Type == cdrEllipseShape) ||
              (s->Type == cdrCurveShape) || (s->Type == cdrPolygonShape) ||
@@ -18,6 +9,7 @@ bool isDPCurve(IVGShapePtr s) {
   return dpc;
 }
 IVGShapePtr CreateBoundary(corel *cdr, IVGShapePtr s) {
+
   auto scp = s->CreateBoundary(0, 0, true, false);
 
   //  这个 API X7 以上才支持,所以现在直接画矩形
@@ -59,9 +51,9 @@ bool isIntWith(corel *cdr, IVGShape *s1, IVGShape *s2) {
 }
 
 // 从矩形边界坐标 获得中心坐标
-void calculate_center(const BoundingBox *box, double *cx, double *cy) {
-  *cx = box->x + (box->w / 2);
-  *cy = box->y + (box->h / 2);
+void calculate_center(const BoundingBox &box, double &cx, double &cy) {
+  cx = box.x + (box.w / 2);
+  cy = box.y + (box.h / 2);
 }
 
 // VGCore::cdrPositionOfPointOverShape VGCore::IVGShape::IsOnShape ( double x,
@@ -73,28 +65,53 @@ bool BoundaryGroup(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs) {
   if (sr->Count < 2)
     return false;
 
-  BoundingBox box;
+  BoundingBox box, bound_box;
   double x, y;
   int OnSh = 0;
+
+  // 处理文字和影响的物件
+  auto txtbox = cdr->CreateShapeRange();
+  auto sr_text =
+      sr->Shapes->FindShapes(_bstr_t(), cdrTextShape, VARIANT_TRUE, _bstr_t());
+  if (sr_text->Count > 0) {
+    auto al = cdr->ActiveLayer;
+    for (auto i = 0; i != sr_text->Count; i++) {
+      sr_text->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box);
+      auto s = al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC);
+      txtbox->Add(s);
+    }
+    sr->AddRange(txtbox);
+  }
+
+  // 建立辅助的异性边界物件,需要填充颜色,搞了半天才搞定
   auto bounds = sr->CreateBoundary(0, 0, true, false); // 建立异性边界物件
   bounds->Fill->UniformColor->RGBAssign(255, 0, 0);    // 填充红色
-
   auto sbox = bounds->BreakApartEx(); // 把边界 拆分为多个边界 用来分组
 
+
+  // 删除文字添加的方框
+  if (sr_text->Count > 0) {
+    sr->RemoveRange(txtbox);
+    txtbox->Delete();
+  }
+
+  // 按照边界框异形范围进行分组群组
   auto srgp = cdr->CreateShapeRange();
 
   for (int k = 0; k < sbox->Count; k++) {
+    sbox->Shapes->Item[k + 1]->GET_BOUNDING_BOX(bound_box);
 
     for (int i = 0; i < sr->Count; i++) {
       auto sh = sr->Shapes->Item[i + 1];
-      sh->GET_BOUNDING_BOX(box);      // 获得物件矩形边界坐标
-      calculate_center(&box, &x, &y); // 获得物件中心坐标
+      sh->GET_BOUNDING_BOX(box);   // 获得物件矩形边界坐标
+      calculate_center(box, x, y); // 获得物件中心坐标
       OnSh = sbox->Shapes->Item[k + 1]->IsOnShape(x, y, -1);
 
       if (OnSh) {
         srgp->Add(sh);
-      } else if (isIntWith(cdr, sbox->Shapes->Item[k + 1], sh)) {
-        srgp->Add(sh);
+      } else if (isOverlapped(box, bound_box)) {
+        if (isIntWith(cdr, sbox->Shapes->Item[k + 1], sh))
+          srgp->Add(sh);
       }
     }
     // 从Range中移除已分组的图形
@@ -102,22 +119,46 @@ bool BoundaryGroup(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs) {
     srs->Add(srgp->Group());
     srgp->RemoveAll();
   }
+
+  // 删除辅助的异性边界物件
   sbox->Delete();
-  
   return true;
 }
 
 // 测试运行 异形群组
 void run_BoundaryGroup(corel *cdr) {
   auto start = std::chrono::high_resolution_clock::now(); // 开始时间
+  if (cdr->VersionMajor < 17) {
+    sprintf(infobuf, "异形群组目前只支持X7以上版本!");
+    return;
+  }
+
   BeginOpt(cdr);
 
   auto sr = cdr->ActiveSelectionRange;
   auto srs = cdr->CreateShapeRange();
+  auto sr_box = cdr->CreateShapeRange();
+
   int cnt = sr->Count;
 
+  // 取消选择,速度优化
   cdr->ActiveDocument->ClearSelection();
-  BoundaryGroup(cdr, sr, srs);
+
+  if (cnt > 300) {
+    // 调用矩形分组,分布执行异形群组
+    if (BoxGrouping(cdr, sr, sr_box, 1.0)) {
+      for (int i = 0; i < sr_box->Count; i++) {
+        auto s = sr_box->Shapes->Item[i + 1];
+        if (!s->IsSimpleShape) {
+          auto sr2 = s->UngroupEx();
+          BoundaryGroup(cdr, sr2, srs);
+        }
+      }
+    }
+  } else {
+    BoundaryGroup(cdr, sr, srs);
+  }
+
   srs->CreateSelection();
 
   // 计算持续时间

+ 3 - 1
09_BoundaryGroup/ToolsBox.cpp

@@ -1,4 +1,5 @@
-#include "cdrapp.h"
+#include "cdrapi.h"
+#include "cdrapp.h"
 #include <stdio.h>
 #include <windows.h>
 #include "resource.h"
@@ -275,6 +276,7 @@ intptr_t CALLBACK ToolsBoxPlugin::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, L
 
         } catch (_com_error &e) {
             MessageBox(NULL, e.Description(), "Error", MB_ICONSTOP);
+            EndOpt(cdr);
         }
 
     } else if (uMsg == WM_INITDIALOG) {

+ 53 - 12
09_BoundaryGroup/boxAutoGroup.cpp

@@ -1,17 +1,5 @@
 #include "cdrapp.h"
 
-#define GET_BOUNDING_BOX(box)                                                  \
-  GetBoundingBox(&(box).x, &(box).y, &(box).w, &(box).h, false)
-
-#define ZERO_4PC 0, 0, 0, 0
-
-typedef struct {
-  double x; // 左下角 x 坐标
-  double y; // 左下角 y 坐标
-  double w; // 宽度
-  double h; // 高度
-} BoundingBox;
-
 // 扩展边界框
 void expand_bounding_boxes(std::vector<BoundingBox>& boxes, double exp) {
     for (auto& box : boxes) {
@@ -202,4 +190,57 @@ bool Box_AutoGroup(corel *cdr, double exp) {
   sprintf(infobuf, "选择物件: %d 个, 分组: %.2f秒\n总共群组: %d 组, 总时间: %.2f秒", 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<BoundingBox> boxes;
+  std::vector<int> 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<int, std::vector<int>> 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();
+  // 分组分别进行群组
+  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;
 }

+ 17 - 0
09_BoundaryGroup/cdrapp.h

@@ -19,6 +19,23 @@ bool BBox_DrawRectangle(corel *cdr, double exp = 0.0);
 
 void run_BoundaryGroup(corel *cdr);
 
+
+
 extern char infobuf[];
 
+#define GET_BOUNDING_BOX(box)                                                  \
+  GetBoundingBox(&(box).x, &(box).y, &(box).w, &(box).h, false)
+
+#define ZERO_4PC 0, 0, 0, 0
+ // 左下角坐标 x,y  w,h 宽高
+typedef struct {
+  double x;
+  double y; 
+  double w; 
+  double h; 
+} BoundingBox;
+
+bool isOverlapped(const BoundingBox &a, const BoundingBox &b);
+bool BoxGrouping(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs, double exp );
+
 #endif // CDRAPP_H_INCLUDED