BoundaryGroup.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "cdrapp.h"
  2. #include <cerrno>
  3. #include <cmath>
  4. #include <cstddef>
  5. bool isDPCurve(IVGShapePtr s) {
  6. auto dpc = (s->Type == cdrRectangleShape) || (s->Type == cdrEllipseShape) ||
  7. (s->Type == cdrCurveShape) || (s->Type == cdrPolygonShape) ||
  8. (s->Type == cdrBitmapShape);
  9. return dpc;
  10. }
  11. IVGShapePtr CreateBoundary(corel *cdr, IVGShapePtr s) {
  12. auto scp = s->CreateBoundary(0, 0, true, false);
  13. // 这个 API X7 以上才支持,所以现在直接画矩形
  14. // BoundingBox box;
  15. // s->GET_BOUNDING_BOX(box);
  16. // auto scp = cdr->ActiveLayer->CreateRectangle2(box.x, box.y, box.w, box.h,
  17. // ZERO_4PC);
  18. return scp;
  19. }
  20. // VGCore::IVGShapePtr VGCore::IVGShape::CreateBoundary ( double x, double y,
  21. // VARIANT_BOOL PlaceOnTop, VARIANT_BOOL DeleteSource ); VGCore::IVGShapePtr
  22. // VGCore::IVGShapeRange::CreateBoundary ( double x, double y, VARIANT_BOOL
  23. // PlaceOnTop, VARIANT_BOOL DeleteSource ); VARIANT_BOOL
  24. // VGCore::IVGCurve::IntersectsWith ( struct IVGCurve * Curve )
  25. bool isIntWith(corel *cdr, IVGShape *s1, IVGShape *s2) {
  26. bool isIn = false;
  27. if (isDPCurve(s1) && isDPCurve(s2)) {
  28. isIn = s1->GetDisplayCurve()->IntersectsWith(s2->GetDisplayCurve());
  29. } else if (isDPCurve(s1)) {
  30. // 群组文字和OLE等其他类型,创建一个临时边界范围
  31. auto scp = CreateBoundary(cdr, s2);
  32. isIn = s1->GetDisplayCurve()->IntersectsWith(scp->GetDisplayCurve());
  33. scp->Delete();
  34. } else if (isDPCurve(s2)) {
  35. auto scp = CreateBoundary(cdr, s1);
  36. isIn = scp->GetDisplayCurve()->IntersectsWith(s2->GetDisplayCurve());
  37. scp->Delete();
  38. } else {
  39. auto scp = CreateBoundary(cdr, s1);
  40. auto scp2 = CreateBoundary(cdr, s2);
  41. isIn = scp->GetDisplayCurve()->IntersectsWith(scp2->GetDisplayCurve());
  42. scp->Delete();
  43. scp2->Delete();
  44. }
  45. return isIn;
  46. }
  47. // 从矩形边界坐标 获得中心坐标
  48. void calculate_center(const BoundingBox &box, double &cx, double &cy) {
  49. cx = box.x + (box.w / 2);
  50. cy = box.y + (box.h / 2);
  51. }
  52. // VGCore::cdrPositionOfPointOverShape VGCore::IVGShape::IsOnShape ( double x,
  53. // double y, double HotArea ); VGCore::cdrPositionOfPointOverShape
  54. // VGCore::IVGCurve::IsOnCurve ( double x, double y, double HotArea );
  55. bool BoundaryGroup(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs) {
  56. if (sr->Count < 2)
  57. return false;
  58. BoundingBox box, bound_box;
  59. double x, y;
  60. int OnSh = 0;
  61. auto red = cdr->CreateCMYKColor(0, 100, 100, 0);
  62. // 处理文字和影响的物件
  63. auto txtbox = cdr->CreateShapeRange();
  64. auto sr_text =
  65. sr->Shapes->FindShapes(_bstr_t(), cdrTextShape, VARIANT_TRUE, _bstr_t());
  66. if (sr_text->Count > 0) {
  67. auto al = cdr->ActiveLayer;
  68. for (auto i = 0; i != sr_text->Count; i++) {
  69. sr_text->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box);
  70. auto s = al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC);
  71. txtbox->Add(s);
  72. }
  73. sr->AddRange(txtbox);
  74. }
  75. // auto stmp = sr->CreateBoundary(0, 0, true, false); // 建立异性边界物件
  76. // auto ef1 = stmp->CreateContour(
  77. // cdrContourOutside, 0.2, 1, cdrDirectFountainFillBlend, red, NULL, NULL, 0,
  78. // 0, cdrContourSquareCap, cdrContourCornerMiteredOffsetBevel, 15);
  79. // auto bounds = ef1->Separate();
  80. // stmp->Delete();
  81. // // bounds->SetOutlineProperties(0.076, NULL, cdr->CreateCMYKColor(100, 50, 0,
  82. // // 0), NULL, NULL, cdrUndefined, cdrUndefined, cdrOutlineUndefinedLineCaps,
  83. // // cdrOutlineUndefinedLineJoin, NULL, NULL, NULL, NULL, NULL);
  84. // auto sbox = bounds->BreakApartEx();
  85. // sbox->ApplyUniformFill(red);
  86. // 建立辅助的异性边界物件,需要填充颜色,搞了半天才搞定
  87. auto bounds = sr->CreateBoundary(0, 0, true, false); // 建立异性边界物件
  88. bounds->Fill->UniformColor->RGBAssign(255, 0, 0); // 填充红色
  89. auto sbox = bounds->BreakApartEx(); // 把边界 拆分为多个边界 用来分组
  90. if (sbox->Count > 2) {
  91. // VGCore::IVGShapeRange::Sort ( _bstr_t CompareExpression, long
  92. // StartIndex, long EndIndex, const _variant_t & Data );
  93. sbox->Sort(
  94. _bstr_t(
  95. "@shape1.width * @shape1.height > @shape2.width * @shape2.height"),
  96. 1, sbox->Count, _variant_t());
  97. }
  98. // 删除文字添加的方框
  99. if (sr_text->Count > 0) {
  100. sr->RemoveRange(txtbox);
  101. txtbox->Delete();
  102. }
  103. // 按照边界框异形范围进行分组群组
  104. auto srgp = cdr->CreateShapeRange();
  105. for (int k = 0; k < sbox->Count && sr->Count; k++) {
  106. sbox->Shapes->Item[k + 1]->GET_BOUNDING_BOX(bound_box);
  107. for (int i = 0; i < sr->Count; i++) {
  108. auto sh = sr->Shapes->Item[i + 1];
  109. sh->GET_BOUNDING_BOX(box); // 获得物件矩形边界坐标
  110. calculate_center(box, x, y); // 获得物件中心坐标
  111. OnSh = sbox->Shapes->Item[k + 1]->IsOnShape(x, y, -1);
  112. if (OnSh) {
  113. srgp->Add(sh);
  114. } else if (isOverlapped(box, bound_box)) {
  115. if (isIntWith(cdr, sbox->Shapes->Item[k + 1], sh))
  116. srgp->Add(sh);
  117. }
  118. }
  119. // 从Range中移除已分组的图形
  120. sr->RemoveRange(srgp);
  121. if (srgp->Count > 1) {
  122. srs->Add(srgp->Group());
  123. } else {
  124. srs->AddRange(srgp);
  125. }
  126. srgp->RemoveAll();
  127. }
  128. // 删除辅助的异性边界物件
  129. if(!debug_flg)
  130. sbox->Delete();
  131. return true;
  132. }
  133. // 测试运行 异形群组
  134. void run_BoundaryGroup(corel *cdr) {
  135. auto start = std::chrono::high_resolution_clock::now(); // 开始时间
  136. if (cdr->VersionMajor < 17) {
  137. sprintf(infobuf, "异形群组目前只支持X7以上版本!");
  138. return;
  139. }
  140. BeginOpt(cdr);
  141. auto sr = cdr->ActiveSelectionRange;
  142. auto srs = cdr->CreateShapeRange();
  143. auto sr_box = cdr->CreateShapeRange();
  144. int cnt = sr->Count;
  145. // 取消选择,速度优化
  146. cdr->ActiveDocument->ClearSelection();
  147. if (cnt > 300) {
  148. // 调用矩形分组,分布执行异形群组
  149. if (BoxGrouping(cdr, sr, sr_box, 0.1)) {
  150. for (int i = 0; i < sr_box->Count; i++) {
  151. auto s = sr_box->Shapes->Item[i + 1];
  152. if (!s->IsSimpleShape) {
  153. auto sr2 = s->UngroupEx();
  154. BoundaryGroup(cdr, sr2, srs);
  155. }
  156. }
  157. }
  158. } else {
  159. BoundaryGroup(cdr, sr, srs);
  160. }
  161. srs->CreateSelection();
  162. // 计算持续时间
  163. double runtime = 0.0;
  164. auto end = std::chrono::high_resolution_clock::now();
  165. std::chrono::duration<double> duration = end - start;
  166. runtime = duration.count();
  167. sprintf(infobuf, "选择物件: %d 个进行异形群组\n群组: %d 组, 时间: %.2f秒",
  168. cnt, srs->Count, runtime);
  169. EndOpt(cdr);
  170. }