Imports SolidEdgeConstants, SolidEdgeFramework
Imports System.Object


Public Class nSidePolygon
    Inherits System.Windows.Forms.Form
    Dim objApp As SolidEdgeFramework.Application
    Dim objDoc As Object
    Dim objRefPlane As Object
    Dim objSketch As SolidEdgePart.Sketch
    Dim objSketchs As SolidEdgePart.Sketchs
    Dim WithEvents objCmd As SolidEdgeFramework.Command
    Dim WithEvents objMouse As SolidEdgeFramework.Mouse
    Dim modelingmode As Short
    Dim selRefPlane As Short
    Dim UOM As SolidEdgeFramework.UnitsOfMeasure
    'This variable is just to improve readability
    Dim UnitDistance As SolidEdgeConstants.UnitTypeConstants = SolidEdgeConstants.UnitTypeConstants.igUnitDistance
    Const WelcomeText As String = "Set options to define the polygon, or click to place it"
    Dim LineEnd As SolidEdgeConstants.KeypointIndexConstants = SolidEdgeConstants.KeypointIndexConstants.igLineEnd
    Dim LineStart As SolidEdgeConstants.KeypointIndexConstants = SolidEdgeConstants.KeypointIndexConstants.igLineStart
    Dim Wrap As String

    Private Sub nSidePolygon_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        ' Failure to end command by setting "Done" can result in the command still running after the form closes!
        If Not objCmd Is Nothing Then
            objCmd.Done = True
        End If
    End Sub

    Private Sub nSidePolygon_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim Origin(1) As Double
        'For readability
        Wrap = Chr(13) & Chr(10)
        lblStatus.Text = "Getting Solid Edge"
        lblType.Text = "Radius from flat"

        Try
            MessageFilter.Register()
            objApp = GetObject(, "SolidEdge.Application")
            objDoc = objApp.ActiveDocument
            objCmd = objApp.CreateCommand(seCmdFlag.seNoDeactivate)
            objMouse = objCmd.Mouse
            objCmd.Start()
            objMouse.LocateMode = seLocateModes.seLocateQuickPick
            objMouse.AddToLocateFilter(SolidEdgeConstants.seLocateFilterConstants.seLocateGeometry2d)
            objMouse.WindowTypes = 1
            objMouse.ClearLocateFilter()
            ' Get a reference to the UnitsOfMeasure object.
            UOM = objApp.ActiveDocument.UnitsOfMeasure

            ' Initialize size
            txtSize.Text = UOM.FormatUnit(UnitDistance, 0.5 * 0.0254)

        Catch ex As Exception
            Call MsgBox("Solid Edge must be running before you start this macro.", MsgBoxStyle.Critical, "Place Polygon")
            End

        End Try
    End Sub

    Private Sub objCmd_Terminate() Handles objCmd.Terminate

        'Terminate the program
        MessageFilter.Revoke()
        End

    End Sub

    Private Sub objMouse_MouseDown(ByVal sButton As Short, ByVal sShift As Short, ByVal dX As Double, ByVal dY As Double, ByVal dZ As Double, ByVal pWindowDispatch As Object, ByVal lKeyPointType As Integer, ByVal pGraphicDispatch As Object) Handles objMouse.MouseDown
        Dim cMsg As String
        Dim Profile As SolidEdgePart.Profile
        Dim ProfileSets As Object
        Dim Lines As SolidEdgeFrameworkSupport.Lines2d
        Dim SegmentLength As Double
        Dim Relations As SolidEdgeFrameworkSupport.Relations2d
        Dim P1(1) As Double, P2(1) As Double, dbl2D(1) As Double
        Dim nSides As Integer
        Dim nSide As Integer
        Dim nAngle As Double
        Dim nRadius As Double
        Dim L() As SolidEdgeFrameworkSupport.Line2d
        Const PI As Double = 3.14159265358979
        Dim activeEnvironment As String
        Dim k, m, count As Integer
        Dim ISECmdEx As ISECommandEx

        Try
            If Not sButton = 1 Then Exit Sub

            ' Starting with ST6, one can use the ISECommandEx interface to begin an undo transaction with a specific
            ' name. Currently Solid Edge ISECommand will automatically create an undo transaction when the Start method
            ' is called. This sample could call BeginUndoTransaction before or after Start is called and all polygons
            ' placed can be undone in Edge at once (current behavior) where the name of the transaction is provided
            ' in the BeginUndoTransaction call (new for ST6). But a separate transaction could be started for each
            ' polygon created, which is what I choose to do. Calling BeginUndoTransaction will terminate the current
            ' transaction and start a new one. Place a number of polygons and then examine the undo list in the undo
            ' dropdown usually located on the quick access bar. There should be one entry for each polygon placement
            ' can be undome indepdently of the others.
            Try
                ISECmdEx = objCmd
                ISECmdEx.BeginUndoTransaction("Place polygon") ' use my string instead of default "nSidedPolygon" Edge will use (macro name)
            Catch ex As Exception
                'Interface not supported in this version of Solid Edge. Nothing to see here. Move along.
            End Try

            activeEnvironment = objApp.ActiveEnvironment.ToUpper
            If objApp.ActiveDocumentType = SolidEdgeFramework.DocumentTypeConstants.igPartDocument Or objApp.ActiveDocumentType = SolidEdgeFramework.DocumentTypeConstants.igSheetMetalDocument Then modelingmode = objDoc.modelingmode

            If activeEnvironment = "LAYOUTINPART" Or activeEnvironment = "PROFILE" Then     ' Assembly and Ordered Part and Sheetmetal
                Profile = objDoc.activesketch
                Lines = Profile.Lines2d
                Relations = Profile.Relations2d
            ElseIf (Not 0 > activeEnvironment.IndexOf("DETAIL")) Or activeEnvironment = "TWODMODEL" Then      'Draft
                ProfileSets = objApp.ActiveDocument.ActiveSheet
                Lines = ProfileSets.lines2d
                Relations = ProfileSets.Relations2d
            ElseIf modelingmode = 1 Then

                ' for some reason a sync sketch when locked does not show up as the active sketch, so need to search the sketches collection.
                objSketchs = objDoc.sketches
                count = objSketchs.Count
                m = 0

                For k = 1 To count
                    If objSketchs.Item(k).Locked = True Then
                        m = k
                        Exit For
                    End If
                Next
                If m = 0 Then
                    MsgBox("There must be a locked sketch to run nSidePolygon in Solid Edge Synchronous Mode.", vbOKOnly + vbCritical)
                    End
                End If
                objSketchs.Item(m).EnableRegions = True
                Profile = objSketchs.Item(m).Profile
                Lines = Profile.Lines2d
                Relations = Profile.Relations2d

            Else
                MsgBox("You are not in a valid environment", vbOKOnly + vbCritical)
                End
            End If

            nSides = Int(Val(txtNumSides.Text))

            If nSides < 3 Then
                MsgBox("The minimum number of sides is 3", vbInformation + vbOKOnly, "Solid Edge Polygon Tool")
                txtNumSides.Text = 3
                Exit Sub
            ElseIf nSides > 360 Then
                MsgBox("The maximum number of sides is 360", vbInformation + vbOKOnly, "Solid Edge Polygon Tool")
                txtNumSides.Text = 360
                Exit Sub
            End If

            If nSides > 20 And chkConstrain.Checked Then
                If MsgBox("The number of sides with automatic constraining will take time to generate. Select yes to autoconstrain, No to abort the process", vbInformation + vbYesNo, "Solid Edge Polygon Tool") = vbNo Then
                    Exit Sub
                End If
            End If

            ReDim L(nSides - 1)

            nAngle = 360.0# / nSides
            nAngle = nAngle * PI / 180.0#

            If optRadFrmFlt.Checked Then
                ' from flat
                nRadius = objApp.ActiveDocument.UnitsOfMeasure.ParseUnit(UnitDistance, txtSize.Text)
                SegmentLength = 2 * nRadius * (Math.Tan(nAngle / 2.0#))
                P2(0) = -(nRadius - dX)
                P2(1) = -((SegmentLength / 2.0#) - dY)
            ElseIf optRadFrmPnt.Checked Then
                ' point
                nRadius = objApp.ActiveDocument.UnitsOfMeasure.ParseUnit(UnitDistance, txtSize.Text)
                SegmentLength = 2 * Math.Sin(nAngle / 2) * nRadius
                P2(0) = -((Math.Cos(nAngle / 2) * nRadius) - dX)
                P2(1) = -((SegmentLength / 2.0#) - dY)
            Else
                ' flat distance
                SegmentLength = objApp.ActiveDocument.UnitsOfMeasure.ParseUnit(UnitDistance, txtSize.Text)
                P2(0) = -((SegmentLength / 2.0#) / (Math.Tan(nAngle / 2.0#)) - dX)
                P2(1) = -((SegmentLength / 2.0#) - dY)
            End If

            For nSide = 0 To nSides - 1
                P1(0) = P2(0)
                P1(1) = P2(1)
                P2(0) = P1(0) + (Math.Sin(nAngle * nSide) * SegmentLength)
                P2(1) = P1(1) + (Math.Cos(nAngle * nSide) * SegmentLength)
                L(nSide) = Lines.AddBy2Points(P1(0), P1(1), P2(0), P2(1))
                lblStatus.Text = "Creating line: " & Format$(nSide, "0")
            Next
            If chkConstrain.Checked Then
                For nSide = 0 To nSides - 1
                    lblStatus.Text = "Adding connect: " & Format$(nSide, "0")
                    If nSide = nSides - 1 Then
                        Call Relations.AddKeypoint(L(nSide), LineEnd, L(0), LineStart)
                    Else
                        Call Relations.AddKeypoint(L(nSide), LineEnd, L(nSide + 1), LineStart)
                        Call Relations.AddEqual(L(nSide), L(nSide + 1))
                    End If
                Next
                objApp.StartCommand(32876) 'View > Refresh
            End If

        Catch ex As Exception
            cMsg = "Error # " & Str(Err.Number) & " was generated by " _
                & Err.Source & Chr(13) & "( " & Err.Description & " )"
            Call MsgBox(cMsg, vbInformation + vbOKOnly, "Solid Edge Polygon Tool")
        End Try

        lblStatus.Text = WelcomeText
    End Sub

    Private Sub optRadFrmFlt_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles optRadFrmFlt.CheckedChanged
        DefinitionTypeChanged()
    End Sub

    Private Sub optRadFrmPnt_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles optRadFrmPnt.CheckedChanged
        DefinitionTypeChanged()
    End Sub

    Private Sub optFlatLength_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles optFlatLength.CheckedChanged
        DefinitionTypeChanged()
    End Sub

    Private Sub DefinitionTypeChanged()
        If optRadFrmFlt.Checked Then
            lblType.Text = "Radius from flat"
            pbxRFF.Visible = True
            pbxRFP.Visible = False
            pbxFL.Visible = False
        ElseIf optRadFrmPnt.Checked Then
            lblType.Text = "Radius from point"
            pbxRFF.Visible = False
            pbxRFP.Visible = True
            pbxFL.Visible = False
        Else
            lblType.Text = "Flat length"
            pbxRFF.Visible = False
            pbxRFP.Visible = False
            pbxFL.Visible = True
        End If
    End Sub

End Class
