메모: 이 기사는 영어로 작성 및 게시되었으며 원본 여기의 번역본입니다.
저는 다른 접근 방식, 즉 대화 또는 수동 조정 없이 깔끔하고 예측 가능한 결과를 생성하는 빠른 단일 클릭 동작에 초점을 맞춘 iLogic 규칙을 작성했습니다.
따라서 일상적인 작업뿐만 아니라 자동화된 프로세스에도 실용적입니다. 기본 제공 Auto Balloon 기능이 API를 통해 노출되지 않으므로, 스크립트 가능한 대체 도구가 이러한 시나리오에서 특히 유용합니다.
생성된 배치는 기본 도구와 동일한 일반적인 아이디어를 따르지만, 품번기호를 부품에 더 가깝게 유지하고 구조화된 결과를 유지하기 위해 몇 가지 작은 조정이 적용됩니다.
개별적인 개선은 미미합니다. 주요 이점은 사용성입니다. 수동 사용과 자동화 모두에 자연스럽게 적합한 신뢰할 수 있는 원클릭 워크플로우입니다.
규칙 사용
- 코드를 외부 iLogic 규칙에 복사합니다.
- (선택 사항) 리본 버튼이나 바로 가기를 추가하여 실행합니다. 오토데스크 가이드:
- 규칙을 실행합니다.
- 도면 뷰를 선택하고 배치가 완료될 때까지 기다립니다.
참고: 도면 곡선이 많은 도면의 경우 규칙이 후보 모서리를 평가하여 부품별로 깔끔한 부착점을 찾기 때문에 시간이 더 오래 걸릴 수 있습니다.
Public Class ThisRule
Private Property DistanceFromEdge As Double = 2
Private Property minimalDistanceBetweenBaloons As Double = 1.4
```
Private Enum Edge
Top
Bottom
Left
Right
End Enum
Sub Main()
Dim doc As DrawingDocument = ThisDoc.Document
Dim sheet As Sheet = doc.ActiveSheet
Dim view As DrawingView = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, "Select a drawing view.")
Dim tagCurves = CollectClosestCurvePerFile(view)
PlaceBalloons(doc, sheet, view, tagCurves)
End Sub
Private Function CollectClosestCurvePerFile(view As DrawingView) As List(Of TagCurve)
Dim viewTop = view.Top
Dim viewBottom = view.Top - view.Height
Dim viewLeft = view.Left
Dim viewRight = view.Left + view.Width
Dim byFile As New Dictionary(Of String, TagCurve)
For Each curve As DrawingCurve In view.DrawingCurves.Cast(Of DrawingCurve)()
' This only works with edges
Try
If TypeOf curve.ModelGeometry IsNot EdgeProxy Then Continue For
Catch
Continue For
End Try
Dim tagCurve As New TagCurve(curve)
If tagCurve.Occ.OccurrencePath.Count > 2 Then Continue For
' Closed curves (circles, ellipses) have no midpoint — fall back to the center.
Dim midPoint As Point2d = curve.MidPoint
If midPoint Is Nothing Then midPoint = curve.CenterPoint
tagCurve.DistanceToNearestViewEdge = MinDistanceToViewEdge(midPoint, viewTop, viewBottom, viewLeft, viewRight)
Dim existing As tagCurve = Nothing
If Not byFile.TryGetValue(tagCurve.FileName, existing) OrElse tagCurve.DistanceToNearestViewEdge < existing.DistanceToNearestViewEdge Then
byFile(tagCurve.FileName) = tagCurve
End If
Next
Return byFile.Values.ToList()
End Function
Private Shared Function MinDistanceToViewEdge(midPoint As Point2d, top As Double, bottom As Double, left As Double, right As Double) As Double
Return Math.Min(
Math.Min(Math.Abs(top - midPoint.Y), Math.Abs(bottom - midPoint.Y)),
Math.Min(Math.Abs(left - midPoint.X), Math.Abs(right - midPoint.X))
)
End Function
Private Sub PlaceBalloons(doc As DrawingDocument, sheet As Sheet, view As DrawingView, tagCurves As List(Of TagCurve))
Dim transientGeom = ThisApplication.TransientGeometry
Dim balloonDiameter = doc.StylesManager.ActiveStandardStyle.ActiveObjectDefaults.BalloonStyle.BalloonDiameter
Dim viewTop = view.Top + DistanceFromEdge
Dim viewBottom = view.Top - view.Height - DistanceFromEdge
Dim viewLeft = view.Left - DistanceFromEdge
Dim viewRight = view.Left + view.Width + DistanceFromEdge
' Phase 1: assign each curve to its closest edge and compute the desired leader endpoint.
Dim placements As New List(Of Placement)
For Each tagCurve As TagCurve In tagCurves
' Closed curves (circles, ellipses) have no midpoint — fall back to the center.
Dim midPoint As Point2d = TagCurve.Curve.MidPoint
If midPoint Is Nothing Then midPoint = TagCurve.Curve.CenterPoint
Dim chosenEdge = ChooseClosestEdge(midPoint, viewTop, viewBottom, viewLeft, viewRight)
Dim leader = ComputeLeaderPoint(chosenEdge, midPoint, viewTop, viewBottom, viewLeft, viewRight, balloonDiameter)
placements.Add(New Placement With {
.TagCurve = TagCurve,
.MidPoint = midPoint,
.ChosenEdge = chosenEdge,
.LeaderX = leader.X,
.LeaderY = leader.Y
})
Next
' Phase 2: per edge, sort by position along that edge, sweep forward to
' enforce minimum spacing, then center each tight cluster so the cluster's
' centroid matches the centroid of its desired positions. Order along the
' edge is preserved either way, so leaders still don't cross.
For Each edgeGroup In placements.GroupBy(Function(p) p.ChosenEdge)
Dim isHorizontal = (edgeGroup.Key = Edge.Top OrElse edgeGroup.Key = Edge.Bottom)
Dim ordered = If(isHorizontal,
edgeGroup.OrderBy(Function(p) p.LeaderX).ToList(),
edgeGroup.OrderBy(Function(p) p.LeaderY).ToList())
Dim desired(ordered.Count - 1) As Double
For i = 0 To ordered.Count - 1
desired(i) = If(isHorizontal, ordered(i).LeaderX, ordered(i).LeaderY)
Next
Dim actual(ordered.Count - 1) As Double
Dim lastPlaced As Double = Double.MinValue
For i = 0 To ordered.Count - 1
actual(i) = Math.Max(desired(i), lastPlaced + minimalDistanceBetweenBaloons)
lastPlaced = actual(i)
Next
' Walk forward and close out each cluster (consecutive balloons in tight
' contact) by shifting it back so sum(actual) = sum(desired) within the
' cluster.
Dim clusterStart = 0
For i = 1 To ordered.Count
If i = ordered.Count OrElse actual(i) - actual(i - 1) > minimalDistanceBetweenBaloons + 0.001 Then
Dim sumActual As Double = 0
Dim sumDesired As Double = 0
For j = clusterStart To i - 1
sumActual += actual(j)
sumDesired += desired(j)
Next
Dim shift = (sumActual - sumDesired) / (i - clusterStart)
For j = clusterStart To i - 1
actual(j) -= shift
Next
clusterStart = i
End If
Next
For i = 0 To ordered.Count - 1
If isHorizontal Then
ordered(i).LeaderX = actual(i)
Else
ordered(i).LeaderY = actual(i)
End If
Next
Next
' Phase 3: create balloons at the final positions.
For Each p In placements
Dim leaderPoints = ThisApplication.TransientObjects.CreateObjectCollection()
leaderPoints.Add(transientGeom.CreatePoint2d(p.LeaderX, p.LeaderY))
leaderPoints.Add(sheet.CreateGeometryIntent(p.TagCurve.Curve, p.MidPoint))
sheet.Balloons.Add(leaderPoints)
Next
End Sub
Private Shared Function ChooseClosestEdge(midPoint As Point2d, top As Double, bottom As Double, left As Double, right As Double) As Edge
Dim distTop = Math.Abs(top - midPoint.Y)
Dim distBottom = Math.Abs(bottom - midPoint.Y)
Dim distLeft = Math.Abs(left - midPoint.X)
Dim distRight = Math.Abs(right - midPoint.X)
Dim horizontalEdge As Edge = If(distTop <= distBottom, Edge.Top, Edge.Bottom)
Dim horizontalDist = Math.Min(distTop, distBottom)
Dim verticalEdge As Edge = If(distLeft <= distRight, Edge.Left, Edge.Right)
Dim verticalDist = Math.Min(distLeft, distRight)
' Tie goes to vertical edge to preserve original behavior
Return If(horizontalDist < verticalDist, horizontalEdge, verticalEdge)
End Function
Private Shared Function ComputeLeaderPoint(edge As Edge, midPoint As Point2d, top As Double, bottom As Double, left As Double, right As Double, balloonDiameter As Double) As (X As Double, Y As Double)
Select Case edge
Case edge.Top
Return (midPoint.X + balloonDiameter / 2, top + balloonDiameter)
Case edge.Bottom
Return (midPoint.X + balloonDiameter / 2, bottom - balloonDiameter)
Case edge.Left
Return (left - balloonDiameter, midPoint.Y + balloonDiameter / 2)
Case Else ' Edge.Right
Return (right + balloonDiameter, midPoint.Y + balloonDiameter / 2)
End Select
End Function
Private Class Placement
Public Property TagCurve As TagCurve
Public Property MidPoint As Point2d
Public Property ChosenEdge As Edge
Public Property LeaderX As Double
Public Property LeaderY As Double
End Class
Public Class TagCurve
Public Sub New(drawingCurve As DrawingCurve)
Curve = drawingCurve
EdgeProxy = drawingCurve.ModelGeometry
Occ = EdgeProxy.ContainingOccurrence.OccurrencePath.Item(1)
FileName = Occ.ReferencedFileDescriptor.FullFileName
End Sub
Public Property FileName As String
Public ReadOnly Property Curve As DrawingCurve
Public Property DistanceToNearestViewEdge As Double
Private ReadOnly EdgeProxy As EdgeProxy
Public Occ As ComponentOccurrence
End Class
```
End Class
추가 iLogic 기반 도면 자동화 도구:
개인 블로그: hjalte.nl - Github - LinkedIn
레이블:
여기에 의견을 추가하려면 등록된 사용자이어야 합니다. 이미 등록되어 있다면 로그인하시기 바랍니다. 아직 등록하지 않은 경우 등록 후 로그인하시기 바랍니다.