Imports Inventor

Public Class Form1
    Private m_InvApp As Inventor.Application = Nothing


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Try
            m_InvApp = GetObject(, "Inventor.Application")
            Dim drawDoc As DrawingDocument = m_InvApp.ActiveDocument
        Catch ex As Exception
            MsgBox("Inventor must be running with a drawing document active.")
        End Try
    End Sub

    Private Sub brnRenumber_Click(sender As Object, e As EventArgs) Handles brnRenumber.Click
        BalloonRenumber(rdoClockwise.Checked)
    End Sub

    Private Sub btnAlign_Click(sender As Object, e As EventArgs) Handles btnAlign.Click
        Dim balloons As New List(Of Balloon)

        Dim drawDoc As DrawingDocument = m_InvApp.ActiveDocument
        For Each obj As Object In drawDoc.SelectSet
            If TypeOf obj Is Balloon Then
                balloons.Add(obj)
            End If
        Next

        If balloons.Count < 2 Then
            MsgBox("There must be at least 2 balloons selected.")
            Return
        End If

        Dim isVertical As Boolean
        If rdoVertical.Checked Then
            isVertical = True
        Else
            isVertical = False
        End If

        BalloonAlign(balloons, isVertical, chkEvenlySpace.Checked)
    End Sub


    ' Renumbers the balloons associated with a view so the balloons are numbered
    ' sequentially around the view.  A balloon must be selected before running the
    ' macro.  The selected balloon defines which balloon will be number 1 and also
    ' defines which view will have its balloons renumbered.  You're also given an
    ' option of having the numbers increase in a clockwise or counterclockwise direction.
    Private Sub BalloonRenumber(isClockwise As Boolean)
        Dim drawDoc As DrawingDocument = m_InvApp.ActiveDocument

        ' Have the balloon selected.
        Dim startBalloon As Balloon = m_InvApp.CommandManager.Pick(SelectionFilterEnum.kDrawingBalloonFilter, "Select the startring balloon.")

        ' Get the view the balloon is attached to.
        Dim parentView As DrawingView = startBalloon.ParentView

        ' Create a Point object that represents the center of the view.
        Dim tg As TransientGeometry = m_InvApp.TransientGeometry
        Dim viewCenter As Point2d = tg.CreatePoint2d(parentView.Left + (parentView.Width / 2),
                                                     parentView.Top - (parentView.Height / 2))

        ' Find all of the other balloons that are attached to the same view
        ' and get the angle each balloon makes relative to the center of the view.
        Dim balloonDatas As List(Of BalloonData) = New List(Of BalloonData)
        For Each balloon As Balloon In parentView.Parent.Balloons
            If balloon.ParentView Is parentView Then
                Dim angle = Bearing(viewCenter, balloon.Position)
                balloonDatas.Add(New BalloonData(balloon, angle))
            End If
        Next

        If isClockwise Then
            balloonDatas = balloonDatas.OrderByDescending(Function(bData) bData.Angle).ToList
        Else
            balloonDatas = balloonDatas.OrderBy(Function(bData) bData.Angle).ToList
        End If

        ' Find the selected balloon within the list.
        Dim startIndex As Long
        For i = 0 To balloonDatas.Count - 1
            If balloonDatas(i).Balloon Is startBalloon Then
                startIndex = i
                Exit For
            End If
        Next

        ' Start a transaction to group all of the edits within a single undo.
        Dim trans As Transaction = m_InvApp.TransactionManager.StartTransaction(drawDoc, "Balloon Renumber")

        ' Edit the set of balloons starting at the selected balloon.
        Dim balloonNumber As Long = 1
        For i = startIndex To balloonDatas.Count - 1
            balloonDatas(i).Balloon.BalloonValueSets.Item(1).Value = Str(balloonNumber)
            balloonNumber += 1
        Next

        ' Edit the set of balloons in the array that ar before the selected balloon.
        For i = 0 To startIndex - 1
            balloonDatas(i).Balloon.BalloonValueSets.Item(1).Value = Str(balloonNumber)
            balloonNumber += 1
        Next

        trans.End()
    End Sub


    Private Class BalloonData
        Public Balloon As Balloon = Nothing
        Public Angle As Double

        Public Sub New(balloon As Balloon, angle As Double)
            Me.Balloon = balloon
            Me.Angle = angle
        End Sub
    End Class


    ' Calculates the angle made between a line defined by the two input points and
    ' the X axis.  The value returned is a value from 0 to 2 pi indicating the direction
    ' from the OriginPoint the DirPoint is in.
    Private Function Bearing(OriginPoint As Point2d, DirPoint As Point2d) As Double
        ' Compute distance between the points.
        Dim Length As Double
        Length = Math.Sqrt(((OriginPoint.X - DirPoint.X) ^ 2) + ((OriginPoint.Y - DirPoint.Y) ^ 2))

        ' Compute angle of line assuming in first quadrant.
        Bearing = Math.Acos(Math.Abs(DirPoint.X - OriginPoint.X) / Length)

        ' Redefine angle based on which quadrant the point is in.
        If DirPoint.X > OriginPoint.X And DirPoint.Y >= OriginPoint.Y Then
            ' Second point is in first quadrant.
            Bearing = Bearing
        ElseIf DirPoint.X <= OriginPoint.X And DirPoint.Y >= OriginPoint.Y Then
            ' Second point is in second quadrant.
            Bearing = Math.PI - Bearing
        ElseIf DirPoint.X <= OriginPoint.X And DirPoint.Y < OriginPoint.Y Then
            ' Second point is in third quadrant.
            Bearing = Math.PI + Bearing
        ElseIf DirPoint.X > OriginPoint.X And DirPoint.Y < OriginPoint.Y Then
            Bearing = (2 * Math.PI) - Bearing
        End If
    End Function

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        Me.Close()
    End Sub

    Private Sub BalloonAlign(Balloons As List(Of Balloon), isVertical As Boolean, isEvenlySpaced As Boolean)
        Dim firstBalloon As Balloon = Balloons.Item(0)

        Dim spacing As Double = 0
        If isEvenlySpaced Then
            ' Determine the spacing.
            If isVertical Then
                Balloons = Balloons.OrderBy(Function(bData) bData.Position.Y).ToList
                spacing = (Balloons(Balloons.Count - 1).Position.Y - Balloons(0).Position.Y) / (Balloons.Count - 1)
            Else
                Balloons = Balloons.OrderBy(Function(bData) bData.Position.X).ToList
                spacing = (Balloons(Balloons.Count - 1).Position.X - Balloons(0).Position.X) / (Balloons.Count - 1)
            End If
        End If

        Dim trans As Transaction = m_InvApp.TransactionManager.StartTransaction(m_InvApp.ActiveDocument, "Balloon Align")

        Dim first As Boolean = True
        Dim lastCoord As Double = 0
        For Each bln As Balloon In Balloons
            Dim pstn = bln.Position
            If isVertical Then
                pstn.X = firstBalloon.Position.X
            Else
                pstn.Y = firstBalloon.Position.Y
            End If

            If isEvenlySpaced Then
                If first Then
                    If isVertical Then
                        lastCoord = bln.Position.Y
                    Else
                        lastCoord = bln.Position.X
                    End If

                    first = False
                Else
                    If isVertical Then
                        pstn.Y = lastCoord + spacing
                        lastCoord = pstn.Y
                    Else
                        pstn.X = lastCoord + spacing
                        lastCoord = pstn.X
                    End If
                End If
            End If

            bln.Position = pstn
        Next

        trans.End()
    End Sub

    Private Sub btnCenter_Click(sender As Object, e As EventArgs) Handles btnCenter.Click
        Dim drawDoc As DrawingDocument = m_InvApp.ActiveDocument
        Dim sht As Sheet = drawDoc.ActiveSheet

        ' Iterate over all of the dimensions.
        For Each drawDim As DrawingDimension In sht.DrawingDimensions
            ' Check to see if the dimension is a linear or angular dimension.
            If TypeOf drawDim Is LinearGeneralDimension Or TypeOf drawDim Is AngularGeneralDimension Then
                ' Center the text.
                drawDim.CenterText()
            End If
        Next
    End Sub
End Class