1
1

SmartGroup.bas 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. Attribute VB_Name = "SmartGroup"
  2. '// This is free and unencumbered software released into the public domain.
  3. '// For more information, please refer to https://github.com/hongwenjun
  4. '// Attribute VB_Name = "智能群组" SmartGroup 2026.05.23 更换AI转的VBA 智能群群租
  5. ' 定义边界框结构
  6. Private Type BoundingBox
  7. X As Double
  8. Y As Double
  9. w As Double
  10. h As Double
  11. End Type
  12. Public Function Smart_Group(Optional ByVal tr As Double = 0) As ShapeRange
  13. On Error GoTo ErrorHandler
  14. API.BeginOpt
  15. Box_AutoGroup_VBA tr '// 2026.05.23 更换AI转的VBA 智能群群租
  16. ErrorHandler:
  17. API.EndOpt
  18. End Function
  19. '// 旧智能群组 原理版
  20. Private Function Smart_Group_ABC()
  21. ActiveDocument.Unit = cdrMillimeter
  22. Dim OrigSelection As ShapeRange, brk1 As ShapeRange
  23. Set OrigSelection = ActiveSelectionRange
  24. Dim s1 As Shape, sh As Shape, s As Shape
  25. Set s1 = OrigSelection.CustomCommand("Boundary", "CreateBoundary")
  26. Set brk1 = s1.BreakApartEx
  27. For Each s In brk1
  28. If s.SizeHeight > 10 Then
  29. Set sh = ActivePage.SelectShapesFromRectangle(s.LeftX, s.topY, s.RightX, s.BottomY, False)
  30. sh.Shapes.all.Group
  31. End If
  32. s.Delete
  33. Next
  34. End Function
  35. ' 1. 检查两个矩形是否重叠 (AABB 碰撞检测)
  36. Private Function IsOverlapped(a As BoundingBox, b As BoundingBox) As Boolean
  37. IsOverlapped = (a.X < b.X + b.w) And (a.X + a.w > b.X) And _
  38. (a.Y < b.Y + b.h) And (a.Y + a.h > b.Y)
  39. End Function
  40. ' 2. 并查集:查找根节点(含路径压缩)
  41. Private Function FindParent(ByRef Parent() As Long, ByVal i As Long) As Long
  42. If Parent(i) <> i Then
  43. Parent(i) = FindParent(Parent, Parent(i))
  44. End If
  45. FindParent = Parent(i)
  46. End Function
  47. ' 3. 并查集:合并集合
  48. Private Sub UnionSet(ByRef Parent() As Long, ByVal X As Long, ByVal Y As Long)
  49. Dim rootX As Long, rootY As Long
  50. rootX = FindParent(Parent, X)
  51. rootY = FindParent(Parent, Y)
  52. If rootX <> rootY Then Parent(rootX) = rootY
  53. End Sub
  54. ' 核心功能:自动分组
  55. Public Function Box_AutoGroup_VBA(Optional ByVal exp As Double = 0)
  56. Dim sr As ShapeRange
  57. Set sr = ActiveSelectionRange
  58. ' 如果没选,尝试全选
  59. If sr.count = 0 Then
  60. ActivePage.Shapes.all.CreateSelection
  61. Set sr = ActiveSelectionRange
  62. End If
  63. If sr.count = 0 Then Exit Function
  64. Dim i As Long, j As Long
  65. Dim count As Long: count = sr.count
  66. Dim boxes() As BoundingBox
  67. Dim parentArr() As Long
  68. ReDim boxes(1 To count)
  69. ReDim parentArr(1 To count)
  70. ' --- 第一步:获取所有形状的边界框并初始化并查集 ---
  71. Dim s As Shape
  72. For i = 1 To count
  73. Set s = sr.Shapes(i)
  74. ' 获取边界框 (VBA 中获取左、下、宽、高)
  75. s.GetBoundingBox boxes(i).X, boxes(i).Y, boxes(i).w, boxes(i).h
  76. ' 扩展边界框 (逻辑同 C++ expand_bounding_boxes)
  77. If Abs(exp) > 0.02 Then
  78. boxes(i).X = boxes(i).X - exp
  79. boxes(i).Y = boxes(i).Y - exp
  80. boxes(i).w = boxes(i).w + 2 * exp
  81. boxes(i).h = boxes(i).h + 2 * exp
  82. End If
  83. parentArr(i) = i ' 初始化父节点为自己
  84. Next i
  85. ' --- 第二步:运行 Union-Find 算法检测重叠 ---
  86. For i = 1 To count
  87. For j = i + 1 To count
  88. If IsOverlapped(boxes(i), boxes(j)) Then
  89. UnionSet parentArr, i, j
  90. End If
  91. Next j
  92. Next i
  93. ' --- 第三步:根据根节点进行物理分组 ---
  94. ' 使用 Collection 模拟 C++ 的 std::map<int, std::vector<int>>
  95. Dim Groups As New Collection
  96. Dim rootID As Long
  97. Dim groupMemberSR As ShapeRange
  98. ' 预处理:将同一组的形状放到一起
  99. ' 我们用数组记录每个根节点对应的 ShapeRange
  100. Dim GroupSRs() As ShapeRange
  101. ReDim GroupSRs(1 To count)
  102. For i = 1 To count
  103. rootID = FindParent(parentArr, i)
  104. If GroupSRs(rootID) Is Nothing Then
  105. Set GroupSRs(rootID) = CreateShapeRange
  106. End If
  107. GroupSRs(rootID).Add sr.Shapes(i)
  108. Next i
  109. ActiveDocument.ClearSelection
  110. ' 遍历并执行 Group 操作
  111. Dim finalSR As New ShapeRange
  112. Dim totalGroups As Long: totalGroups = 0
  113. For i = 1 To count
  114. If Not GroupSRs(i) Is Nothing Then
  115. If GroupSRs(i).count > 1 Then
  116. finalSR.Add GroupSRs(i).Group
  117. totalGroups = totalGroups + 1
  118. Else
  119. finalSR.Add GroupSRs(i)(1)
  120. totalGroups = totalGroups + 1
  121. End If
  122. End If
  123. Next i
  124. finalSR.CreateSelection
  125. End Function