Export to STEP with CHATGPT

Export to STEP with CHATGPT

Ivan_Sinicyn
Advocate Advocate
1,591 Views
6 Replies
Message 1 of 7

Export to STEP with CHATGPT

Ivan_Sinicyn
Advocate
Advocate

I don't know any programming language. I have tried several times to familiarize myself with vbnet, but I don't have enough time for all that. I very often export files to step format with different settings. Each time, exporting one file at a time was just tiring. I tried to find an off-the-shelf solution, but didn't find one. I tried several times to use large language models such as CHATGPT. Before version 4.0, it required basic programming knowledge for edits after code generation, but yesterday I tried version 4o and was shocked. CHATGPT wrote valid code from the beginning, taking into account only my requests. When the code grew up to 200 lines, the first errors and difficulties started. Sometimes I would just dump the log and CHATGPT would fix the errors in the new version by itself. Sometimes I found similar problems on forums or API reference and fed them into the CHATGPT window. The problems were solved again. Now there are about 700 lines of code in the script that closes all my requests. I spent about 12 hours on this, half of which was spent generating the script from the beginning. Since I don't know how to edit code manually, I asked CHATGPT to generate it from the beginning each time with all edits.

I am attaching the ILogic code to the post. It may be useful for someone.

The script settings are saved in c:\Users\%CURRENTUSER%\AppData\Roaming\FSTEPExport\ folder.

The folder and settings file are created the first time you press the SAVE button.

Imports Inventor
Imports System.IO
Imports System.Windows.Forms

Public Class PathInputForm
    Inherits System.Windows.Forms.Form

    Public Property OutputPath As String
    Public Property OverwriteFiles As Boolean
    Public Property DistributeByMaterial As Boolean
    Public Property IncludeQuantity As Boolean ' New property for checkbox
    Public Property FilterSheetMetal As Boolean ' New property for checkbox

    Private textBox As System.Windows.Forms.TextBox
    Private buttonOK As System.Windows.Forms.Button
    Private buttonCancel As System.Windows.Forms.Button
    Private buttonAuto As System.Windows.Forms.Button
    Private buttonDefault As System.Windows.Forms.Button
    Private buttonBrowse As System.Windows.Forms.Button
    Private buttonSavePath As System.Windows.Forms.Button ' New button to save path
    Private buttonClear As System.Windows.Forms.Button ' New button to clear folder
    Private buttonSaveSettings As System.Windows.Forms.Button ' New button to save settings
    Private checkBoxOverwrite As System.Windows.Forms.CheckBox
    Private checkBoxDistribute As System.Windows.Forms.CheckBox
    Private checkBoxIncludeQuantity As System.Windows.Forms.CheckBox ' New checkbox
    Private checkBoxFilterSheetMetal As System.Windows.Forms.CheckBox ' New checkbox
    Private groupBoxPath As System.Windows.Forms.GroupBox
    Private assemblyFolderPath As String
    Private toolTip As System.Windows.Forms.ToolTip
    Private settingsManager As settingsManager

    Public Sub New(assemblyFolderPath As String)
        Me.assemblyFolderPath = assemblyFolderPath
        Me.Text = "FSTEPExport"
        Me.Width = 450
        Me.Height = 400 ' Increase height to accommodate new elements
        Me.StartPosition = FormStartPosition.CenterScreen ' Center the window on the screen

        toolTip = New System.Windows.Forms.ToolTip()
        settingsManager = New SettingsManager("settings.txt")

        groupBoxPath = New System.Windows.Forms.GroupBox()
        groupBoxPath.Text = "Save Path"
        groupBoxPath.Width = 400
        groupBoxPath.Height = 120
        groupBoxPath.Top = 10
        groupBoxPath.Left = 20

        textBox = New System.Windows.Forms.TextBox()
        textBox.Width = 370
        textBox.Top = 20
        textBox.Left = 10
        textBox.Text = settingsManager.LoadDefaultPath() ' Load default path

        buttonAuto = New System.Windows.Forms.Button()
        buttonAuto.Text = "Auto"
        buttonAuto.Top = 50
        buttonAuto.Left = 10
        buttonAuto.Width = 120
        AddHandler buttonAuto.Click, Sub(sender, e)
                                         If Not String.IsNullOrEmpty(assemblyFolderPath) Then
                                             textBox.Text = System.IO.Path.Combine(assemblyFolderPath, "STEP")
                                         Else
                                             MessageBox.Show("assemblyFolderPath is not initialized.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                                         End If
                                     End Sub
        toolTip.SetToolTip(buttonAuto, "The path is set according to the assembly location.")

        buttonDefault = New System.Windows.Forms.Button()
        buttonDefault.Text = "Default"
        buttonDefault.Top = 50
        buttonDefault.Left = 140
        buttonDefault.Width = 120
        AddHandler buttonDefault.Click, Sub(sender, e)
                                            textBox.Text = settingsManager.LoadDefaultPath()
                                        End Sub
        toolTip.SetToolTip(buttonDefault, "The path is set according to the data recorded in the file.")

        buttonSavePath = New System.Windows.Forms.Button() ' New button to save path
        buttonSavePath.Text = "*"
        buttonSavePath.Top = 50
        buttonSavePath.Left = 270
        buttonSavePath.Width = 40
        AddHandler buttonSavePath.Click, AddressOf Me.ButtonSavePath_Click
        toolTip.SetToolTip(buttonSavePath, "Save path for 'Default' button")

        buttonBrowse = New System.Windows.Forms.Button()
        buttonBrowse.Text = "Browse..."
        buttonBrowse.Top = 50
        buttonBrowse.Left = 320
        buttonBrowse.Width = 60
        AddHandler buttonBrowse.Click, AddressOf Me.ButtonBrowse_Click
        toolTip.SetToolTip(buttonBrowse, "Select another export folder.")

        groupBoxPath.Controls.Add(textBox)
        groupBoxPath.Controls.Add(buttonAuto)
        groupBoxPath.Controls.Add(buttonDefault)
        groupBoxPath.Controls.Add(buttonSavePath)
        groupBoxPath.Controls.Add(buttonBrowse)

        checkBoxOverwrite = New System.Windows.Forms.CheckBox()
        checkBoxOverwrite.Text = "Overwrite existing files"
        checkBoxOverwrite.Top = 140
        checkBoxOverwrite.Left = 20
        checkBoxOverwrite.Width = 400
        checkBoxOverwrite.Checked = True ' Set checkbox to be checked by default

        checkBoxDistribute = New System.Windows.Forms.CheckBox()
        checkBoxDistribute.Text = "Distribute by material"
        checkBoxDistribute.Top = 170
        checkBoxDistribute.Left = 20
        checkBoxDistribute.Width = 400

        checkBoxIncludeQuantity = New System.Windows.Forms.CheckBox() ' New checkbox
        checkBoxIncludeQuantity.Text = "Include quantity in export file"
        checkBoxIncludeQuantity.Top = 200
        checkBoxIncludeQuantity.Left = 20
        checkBoxIncludeQuantity.Width = 400
        checkBoxIncludeQuantity.AutoSize = True ' Ensure the text is in one line
        checkBoxIncludeQuantity.Checked = True ' Set checkbox to be checked by default

        checkBoxFilterSheetMetal = New System.Windows.Forms.CheckBox() ' New checkbox
        checkBoxFilterSheetMetal.Text = "Exclude sheet metal"
        checkBoxFilterSheetMetal.Top = 230
        checkBoxFilterSheetMetal.Left = 20
        checkBoxFilterSheetMetal.Width = 400
        checkBoxFilterSheetMetal.AutoSize = True ' Ensure the text is in one line
        checkBoxFilterSheetMetal.Checked = True ' Set checkbox to be checked by default

        buttonClear = New System.Windows.Forms.Button() ' New button to clear folder
        buttonClear.Text = "Clear folder"
        buttonClear.Top = 260
        buttonClear.Left = 20
        buttonClear.Width = 120
        AddHandler buttonClear.Click, AddressOf Me.ButtonClear_Click
        toolTip.SetToolTip(buttonClear, "Delete all files in the destination folder")

        buttonSaveSettings = New System.Windows.Forms.Button() ' New button to save settings
        buttonSaveSettings.Text = "Save"
        buttonSaveSettings.Top = 260
        buttonSaveSettings.Left = 150
        buttonSaveSettings.Width = 120
        AddHandler buttonSaveSettings.Click, AddressOf Me.ButtonSaveSettings_Click
        toolTip.SetToolTip(buttonSaveSettings, "Save checkbox settings")

        buttonOK = New System.Windows.Forms.Button()
        buttonOK.Text = "Export"
        buttonOK.Top = 290
        buttonOK.Left = 280
        buttonOK.Width = 120
        AddHandler buttonOK.Click, AddressOf Me.ButtonOK_Click

        buttonCancel = New System.Windows.Forms.Button()
        buttonCancel.Text = "Cancel"
        buttonCancel.Top = 290
        buttonCancel.Left = 150
        buttonCancel.Width = 120
        AddHandler buttonCancel.Click, AddressOf Me.ButtonCancel_Click

        Me.Controls.Add(groupBoxPath)
        Me.Controls.Add(buttonOK)
        Me.Controls.Add(buttonCancel)
        Me.Controls.Add(checkBoxOverwrite)
        Me.Controls.Add(checkBoxDistribute)
        Me.Controls.Add(checkBoxIncludeQuantity) ' Add checkbox to form
        Me.Controls.Add(checkBoxFilterSheetMetal) ' Add checkbox to form
        Me.Controls.Add(buttonClear) ' Add button to form
        Me.Controls.Add(buttonSaveSettings) ' Add button to form

        LoadSettings()
    End Sub

    Private Sub ButtonSavePath_Click(sender As Object, e As EventArgs)
        settingsManager.SaveDefaultPath(textBox.Text)
        MessageBox.Show("Default path saved.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

    Private Sub ButtonClear_Click(sender As Object, e As EventArgs)
        If MessageBox.Show("Are you sure you want to delete all files in the destination folder?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
            Try
                For Each file As String In System.IO.Directory.GetFiles(textBox.Text)
                    System.IO.File.Delete(File)
                Next
                For Each dir As String In System.IO.Directory.GetDirectories(textBox.Text)
                    System.IO.Directory.Delete(Dir, True)
                Next
                MessageBox.Show("Destination folder cleared.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Catch ex As Exception
                MessageBox.Show("Error clearing destination folder: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End If
    End Sub

    Private Sub ButtonSaveSettings_Click(sender As Object, e As EventArgs)
        SaveSettings()
        MessageBox.Show("Settings saved.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

    Private Sub ButtonOK_Click(sender As Object, e As EventArgs)
        SaveSettings()
        Me.OutputPath = textBox.Text
        Me.OverwriteFiles = checkBoxOverwrite.Checked
        Me.DistributeByMaterial = checkBoxDistribute.Checked
        Me.IncludeQuantity = checkBoxIncludeQuantity.Checked ' Save checkbox state
        Me.FilterSheetMetal = checkBoxFilterSheetMetal.Checked ' Save checkbox state
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub

    Private Sub ButtonCancel_Click(sender As Object, e As EventArgs)
        Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
        Me.Close()
    End Sub

    Private Sub ButtonBrowse_Click(sender As Object, e As EventArgs)
        Using folderBrowser As New FolderBrowserDialog()
            folderBrowser.Description = "Select a folder to save .step files"
            folderBrowser.SelectedPath = assemblyFolderPath ' Set initial folder
            If folderBrowser.ShowDialog() = DialogResult.OK Then
                textBox.Text = folderBrowser.SelectedPath
            End If
        End Using
    End Sub

    Private Sub SaveSettings()
        settingsManager.SaveCheckBoxState(checkBoxOverwrite, "OverwriteFiles")
        settingsManager.SaveCheckBoxState(checkBoxDistribute, "DistributeByMaterial")
        settingsManager.SaveCheckBoxState(checkBoxIncludeQuantity, "IncludeQuantity")
        settingsManager.SaveCheckBoxState(checkBoxFilterSheetMetal, "FilterSheetMetal")
    End Sub

    Private Sub LoadSettings()
        settingsManager.LoadCheckBoxState(checkBoxOverwrite, "OverwriteFiles")
        settingsManager.LoadCheckBoxState(checkBoxDistribute, "DistributeByMaterial")
        settingsManager.LoadCheckBoxState(checkBoxIncludeQuantity, "IncludeQuantity")
        settingsManager.LoadCheckBoxState(checkBoxFilterSheetMetal, "FilterSheetMetal")
    End Sub
End Class

Public Class SettingsManager
    Private settingsFilePath As String

    ' Constructor accepts the settings file name
    Public Sub New(settingsFileName As String)
        Dim settingsFolder As String = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "FSTEPExport")
        If Not System.IO.Directory.Exists(settingsFolder) Then
            System.IO.Directory.CreateDirectory(settingsFolder)
        End If
        settingsFilePath = System.IO.Path.Combine(settingsFolder, settingsFileName)
    End Sub

    ' Method to save the state of checkboxes
    Public Sub SaveCheckBoxState(checkBox As CheckBox, id As String)
        Dim settings As New List(Of String)
        If System.IO.File.Exists(settingsFilePath) Then
            settings.AddRange(System.IO.File.ReadAllLines(settingsFilePath))
        End If

        Dim index As Integer = settings.FindIndex(Function(line) line.StartsWith(id & "="))
        Dim newLine As String = id & "=" & checkBox.Checked.ToString() & " ' " & checkBox.Text

        If index >= 0 Then
            settings(index) = newLine
        Else
            settings.Add(newLine)
        End If

        System.IO.File.WriteAllLines(settingsFilePath, settings)
    End Sub

    ' Method to load the state of checkboxes
    Public Sub LoadCheckBoxState(checkBox As CheckBox, id As String)
        If System.IO.File.Exists(settingsFilePath) Then
            Dim settings As String() = System.IO.File.ReadAllLines(settingsFilePath)
            For Each setting As String In settings
                If setting.StartsWith(id & "=") Then
                    Dim value As String = setting.Split("="c)(1).Split("'"c)(0).Trim()
                    Boolean.TryParse(value, checkBox.Checked)
                End If
            Next
        Else
            checkBox.Checked = True ' Set default value if file does not exist
        End If
    End Sub

    ' Method to save the default path
    Public Sub SaveDefaultPath(path As String)
        Dim settings As New List(Of String)
        If System.IO.File.Exists(settingsFilePath) Then
            settings.AddRange(System.IO.File.ReadAllLines(settingsFilePath))
        End If

        Dim index As Integer = settings.FindIndex(Function(line) line.StartsWith("DefaultPath="))
        Dim newLine As String = "DefaultPath=" & path & " ' Default path"

        If index >= 0 Then
            settings(index) = newLine
        Else
            settings.Add(newLine)
        End If

        System.IO.File.WriteAllLines(settingsFilePath, settings)
    End Sub

    ' Method to load the default path
    Public Function LoadDefaultPath() As String
        If System.IO.File.Exists(settingsFilePath) Then
            Dim settings As String() = System.IO.File.ReadAllLines(settingsFilePath)
            For Each setting As String In settings
                If setting.StartsWith("DefaultPath=") Then
                    Return setting.Split("="c)(1).Split("'"c)(0).Trim()
                End If
            Next
        End If
        Return "C:\DXF" ' Default value if file does not exist
    End Function
End Class

Sub Main()
    ' Get the active document
    Dim invApp As Inventor.Application = ThisApplication
    Dim activeDoc As Document = invApp.ActiveDocument

    ' Check if the document is an assembly
    If activeDoc.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
        System.Windows.Forms.MessageBox.Show("Open an assembly file to run this script.")
        Return
    End If

    ' Check current selection priority
    If activeDoc.SelectionPriority <> 67591 Then
        ' If selection priority is different from part selection, show a warning and change priority
        MsgBox("Selection mode is different from part selection. The mode will be changed. Please reselect the parts and try again.", vbExclamation + vbOKOnly, "Warning")
        activeDoc.SelectionPriority = 67591

        ' Deselect all selected components
        Dim oSelectSet As SelectSet
        oSelectSet = activeDoc.SelectSet
        oSelectSet.Clear()
        Return
    End If

    ' Get the assembly document
    Dim asmDoc As AssemblyDocument = activeDoc
    Dim asmCompDef As AssemblyComponentDefinition = asmDoc.ComponentDefinition

    ' Get all selected components in the assembly
    Dim selectedObjects As ObjectCollection = invApp.TransientObjects.CreateObjectCollection()
    For Each obj In invApp.ActiveDocument.SelectSet
        If TypeOf obj Is ComponentOccurrence Then
            selectedObjects.Add(obj)
        End If
    Next

    ' If no components are selected, display a message and end the script
    If selectedObjects.Count = 0 Then
        System.Windows.Forms.MessageBox.Show("Select parts for export and try again.")
        Return
    End If

    ' Create a dictionary to store unique part numbers and materials
    Dim uniqueParts As New HashSet(Of String)
    Dim materialDict As New Dictionary(Of String, String)

    ' Create a dictionary to store the number of occurrences of each part
    Dim partDict As New Dictionary(Of String, Integer)

    ' Show the form to enter the path
    Dim form As New PathInputForm(System.IO.Path.GetDirectoryName(activeDoc.FullFileName))
    If form.ShowDialog() <> DialogResult.OK Then
        Return
    End If

    Dim outputFolder As String = form.OutputPath
    Dim overwriteFiles As Boolean = form.OverwriteFiles
    Dim distributeByMaterial As Boolean = form.DistributeByMaterial
    Dim includeQuantity As Boolean = form.IncludeQuantity ' Save checkbox state
    Dim filterSheetMetal As Boolean = form.FilterSheetMetal ' Save checkbox state

    ' Iterate through all selected components of the assembly and subassemblies
    For Each oSelectedOcc As ComponentOccurrence In selectedObjects
        ' Check the BOM structure type
        Dim bomStructure As BOMStructureEnum = oSelectedOcc.Definition.BOMStructure
        If bomStructure = BOMStructureEnum.kPurchasedBOMStructure OrElse bomStructure = BOMStructureEnum.kPhantomBOMStructure OrElse bomStructure = BOMStructureEnum.kReferenceBOMStructure OrElse bomStructure = BOMStructureEnum.kInseparableBOMStructure Then
            Continue For
        End If

        ' Filter sheet metal
        If filterSheetMetal AndAlso IsSheetMetal(oSelectedOcc) Then
            Continue For
        End If

        ' Get the part number
        Dim partNumber As String = oSelectedOcc.Definition.Document.PropertySets.Item("Design Tracking Properties").Item("Part Number").Value

        ' Add the part number to the unique set
        uniqueParts.Add(partNumber)
    Next

    ' Count all occurrences of unique parts in the assembly and subassemblies
    CountOccurrences(asmCompDef.Occurrences, uniqueParts, partDict, materialDict, filterSheetMetal)

    ' Check the existence of the folder and create it if necessary
    If Not System.IO.Directory.Exists(outputFolder) Then
        System.IO.Directory.CreateDirectory(outputFolder)
    End If

    ' Check for the existence of the STEP export add-in
    Dim addInId As String = "{90AF7F40-0C01-11D5-8E83-0010B541CD80}"
    Dim oExport As TranslatorAddIn = Nothing

    Try
        oExport = invApp.ApplicationAddIns.ItemById(addInId)
        If oExport Is Nothing Then
            System.Windows.Forms.MessageBox.Show("STEP Translator add-in not found.")
            Return
        End If

        ' Activate the add-in if it is not activated
        If Not oExport.Activated Then
            oExport.Activate()
            If Not oExport.Activated Then
                System.Windows.Forms.MessageBox.Show("Failed to activate STEP Translator add-in.")
                Return
            End If
        End If
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show("Error getting TranslatorAddIn: " & ex.Message)
        Return
    End Try

    ' Export each part to a .step file, taking into account the number of occurrences
    Dim exportedFiles As Integer = 0
    Dim overwrittenFiles As Integer = 0
    Dim skippedFiles As Integer = 0
    For Each kvp As KeyValuePair(Of String, Integer) In partDict
        ' Get the part number and quantity
        Dim partNumber As String = kvp.Key
        Dim qty As Integer = kvp.Value

        ' Get the part material from the dictionary
        Dim material As String = materialDict(partNumber)

        ' Create the output file name
        Dim materialFolder As String = outputFolder
        If distributeByMaterial Then
            materialFolder = System.IO.Path.Combine(outputFolder, material)
            If Not System.IO.Directory.Exists(materialFolder) Then
                System.IO.Directory.CreateDirectory(materialFolder)
            End If
        End If

        ' Modify the file name depending on the state of includeQuantity
        Dim outputFileName As String
        If includeQuantity Then
            outputFileName = System.IO.Path.Combine(materialFolder, partNumber & " - " & qty.ToString() & ".step")
        Else
            outputFileName = System.IO.Path.Combine(materialFolder, partNumber & ".step")
        End If

        ' Check if a file with the same partNumber exists and whether it needs to be overwritten
        Dim existingFiles As String() = System.IO.Directory.GetFiles(materialFolder, partNumber & "*.step")
        If existingFiles.Length > 0 AndAlso Not overwriteFiles Then
            skippedFiles += 1
            Continue For
        End If

        ' Delete all files with the same partNumber when overwriting
        If overwriteFiles Then
            DeleteFilesByPartNumber(outputFolder, partNumber)
            If distributeByMaterial Then
                DeleteFilesByPartNumber(materialFolder, partNumber)
            End If
        End If

        ' Get the part document via ComponentDefinition
        Dim partDoc As Document = GetPartDocument(asmCompDef.Occurrences, partNumber)

        ' Check that partDoc is not Nothing
        If partDoc Is Nothing Then
            System.Windows.Forms.MessageBox.Show("Failed to find document for part: " & partNumber)
            Continue For
        End If

        ' Create export options
        Dim oContext As TranslationContext = invApp.TransientObjects.CreateTranslationContext
        oContext.Type = IOMechanismEnum.kFileBrowseIOMechanism

        Dim oOptions As NameValueMap = invApp.TransientObjects.CreateNameValueMap
        If oExport.HasSaveCopyAsOptions(partDoc, oContext, oOptions) Then
            oOptions.Value("ApplicationProtocolType") = 214 ' AP214
        End If

        Dim oData As DataMedium = invApp.TransientObjects.CreateDataMedium
        oData.FileName = outputFileName

        ' Perform the export
        Try
            oExport.SaveCopyAs(partDoc, oContext, oOptions, oData)
            exportedFiles += 1
            If System.IO.File.Exists(outputFileName) Then
                overwrittenFiles += 1
            End If
        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show("Error exporting part " & partNumber & ": " & ex.Message)
        End Try
    Next

    ' Delete empty subdirectories
    If overwriteFiles Then
        DeleteEmptyDirectories(outputFolder)
    End If

    Dim message As String = "Export completed." & vbCrLf & "Files saved to: " & outputFolder & vbCrLf
    message &= "Number of unique files: " & exportedFiles.ToString() & vbCrLf
    If overwrittenFiles > 0 Then
        message &= "Number of overwritten files: " & overwrittenFiles.ToString() & vbCrLf
    End If
    If skippedFiles > 0 Then
        message &= "Number of skipped files: " & skippedFiles.ToString()
    End If

    Dim resultForm As New ExportResultForm(message, outputFolder)
    resultForm.ShowDialog()
End Sub

Private Sub CountOccurrences(occurrences As ComponentOccurrences, uniqueParts As HashSet(Of String), partDict As Dictionary(Of String, Integer), materialDict As Dictionary(Of String, String), filterSheetMetal As Boolean)
    For Each occ As ComponentOccurrence In occurrences
        If TypeOf occ.Definition.Document Is PartDocument Then
            Dim partNumber As String = occ.Definition.Document.PropertySets.Item("Design Tracking Properties").Item("Part Number").Value

            ' Filter sheet metal
            If filterSheetMetal AndAlso IsSheetMetal(occ) Then
                Continue For
            End If

            If uniqueParts.Contains(partNumber) Then
                If partDict.ContainsKey(partNumber) Then
                    partDict(partNumber) += 1
                Else
                    partDict(partNumber) = 1
                End If

                ' Get the part material and add it to the dictionary
                Dim material As String = GetMaterialForPart(occ.Definition.Document)
                If Not materialDict.ContainsKey(partNumber) Then
                    materialDict(partNumber) = material
                End If
            End If
        ElseIf TypeOf occ.Definition.Document Is AssemblyDocument Then
            CountOccurrences(occ.SubOccurrences, uniqueParts, partDict, materialDict, filterSheetMetal)
        End If
    Next
End Sub

Private Function GetPartDocument(occurrences As ComponentOccurrences, partNumber As String) As Document
    For Each occ As ComponentOccurrence In occurrences
        If TypeOf occ.Definition.Document Is PartDocument Then
            If occ.Definition.Document.PropertySets.Item("Design Tracking Properties").Item("Part Number").Value = partNumber Then
                Return occ.Definition.Document
            End If
        ElseIf TypeOf occ.Definition.Document Is AssemblyDocument Then
            Dim doc As Document = GetPartDocument(occ.SubOccurrences, partNumber)
            If doc IsNot Nothing Then
                Return doc
            End If
        End If
    Next
    Return Nothing
End Function

Private Function GetMaterialForPart(doc As Document) As String
    Try
        Return doc.ComponentDefinition.Material.Name
    Catch ex As Exception
        Return ""
    End Try
End Function

Private Sub DeleteFilesByPartNumber(folder As String, partNumber As String)
    Dim dirInfo As New DirectoryInfo(folder)

    ' Delete files from the root folder
    Dim filesToDelete As FileInfo() = dirInfo.GetFiles(partNumber & "*.step")
    For Each file As FileInfo In filesToDelete
        File.Delete()
    Next

    ' Delete files from subdirectories
    Dim subDirs As DirectoryInfo() = dirInfo.GetDirectories()
    For Each dir As DirectoryInfo In subDirs
        filesToDelete = Dir.GetFiles(partNumber & "*.step")
        For Each file As FileInfo In filesToDelete
            File.Delete()
        Next
    Next
End Sub

Private Sub DeleteEmptyDirectories(ByVal directory As String)
    Dim rootDirectoryInfo As New DirectoryInfo(directory)
    Dim directoriesToCheck As DirectoryInfo() = rootDirectoryInfo.GetDirectories("*", SearchOption.AllDirectories)
    For Each subDirectory As DirectoryInfo In directoriesToCheck
        If subDirectory.GetFiles().Length = 0 AndAlso subDirectory.GetDirectories().Length = 0 Then
            subDirectory.Delete()
        End If
    Next
End Sub

Private Function IsSheetMetal(occ As ComponentOccurrence) As Boolean
    Try
        Return occ.Definition.Document.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}"
    Catch ex As Exception
        Return False
    End Try
End Function

Public Class ExportResultForm
    Inherits Form

    Public Sub New(message As String, outputFolder As String)
        Me.Text = "Export Results"
        Me.Width = 400
        Me.Height = 200
        Me.StartPosition = FormStartPosition.CenterScreen

        Dim label As New Label()
        label.Text = message
        label.AutoSize = True
        label.Top = 20
        label.Left = 20

        Dim buttonOpenFolder As New Button()
        buttonOpenFolder.Text = "Open folder"
        buttonOpenFolder.AutoSize = True
        buttonOpenFolder.Top = 100
        buttonOpenFolder.Left = 20
        AddHandler buttonOpenFolder.Click, Sub(sender, e)
                                               Process.Start("explorer.exe", outputFolder)
                                           End Sub

        Dim buttonOK As New Button()
        buttonOK.Text = "OK"
        buttonOK.Top = 100
        buttonOK.Left = 300
        AddHandler buttonOK.Click, Sub(sender, e)
                                       Me.Close()
                                   End Sub

        Me.Controls.Add(label)
        Me.Controls.Add(buttonOpenFolder)
        Me.Controls.Add(buttonOK)
    End Sub
End Class



FSEXP1.png

FSEXP2.png

FSEXP3.png

   

INV 2025.3
0 Likes
1,592 Views
6 Replies
Replies (6)
Message 2 of 7

jbrammer6U3Y8
Community Visitor
Community Visitor

Made any progress in the last 18 months? I was about to get started on something like this and am looking for starting points. Assuming so since GPT and now its Codex have come a long way since your post.

0 Likes
Message 3 of 7

J_Pfeifer_
Advocate
Advocate

Start small, how does one recognize patterns when you ask for a complete program from chat GPT? An ocean of context without the ability to parse out every section and its function. 

 

Hint: Stop trying to get chat GPT to program something for you. Spending 18 hours with different prompts that all end up in near the same spot or Starting with the first task, asking AI what and how that small part works. Then you add, and add, and add more and more context and patterns. Eventually, you're only asking the AI to cover topics you know about but may not understand fully. You then are better equip when coming to the forums. 

 

There's always something people say in different industries and professions. You have to actually do it. Welders need hood time, programmers need writing time, drivers and pilots need seat time. You get no where looking for a silver bullet. Something to think about, why are you the second person to comment on this thread in a year? Those 18 hours should have went into seat time anyone that would love to help can't given the information provided. Unless they want to take on 90% of the project. 

Message 4 of 7

Ivan_Sinicyn
Advocate
Advocate

Everything written above is correct. Great things start small. For today, I would recommend using GROK to write simple ILogic programs. It has an excellent understanding of the Inventor API and a very high success rate in fulfilling your requests.

The program mentioned in the first post is so primitive that I’ve already forgotten about it. With the advent of agent-based systems such as Codex, Gemini CLI, and of course Claude Code, tasks are now solved tens of times faster.

It is very important during this process to learn the terminology of the Inventor API — once you do, the success rate of writing the exact function you need will increase manyfold.

I have already created more than a dozen auxiliary plugins and programs to assist with daily work. One of the largest and most public ones is Flat Pattern DXF Exporter - Autodesk Community. It has a rather mixed architecture and tangled code because I started developing it back in the days of ChatGPT-4o, but every time I use it, it continues to delight me with its convenience.



INV 2025.3
0 Likes
Message 5 of 7

A.Acheson
Mentor
Mentor

I suggest to open the inventor API help and familiarize yourself with the objects then you can see where the code that is in the forum comes from. It's like following a path to the mountain top. There are many paths and places to stop along the way. The API samples are VBA based mostly, learn to plug them into VBA editor and check what they do. Then learn to convert to VB.Net, mostly drop the word "set" and create "Sub Main". Once you know what to convert you have access to whole library of knowledge. 

 

Learn how to use this sample traverse assembly and it's like a key to the castle. A book explaining its components and meanings. 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 6 of 7

jbrammer6U3Y8
Community Visitor
Community Visitor

Thanks for quick responses, but I didn’t mean to imply that I don’t know how to start, I was wondering whether someone had already built and shared one and I just hadn’t managed to find it. It only took a few passes with GPT and Codex to get a working add-in to export into a GPT workable json right after I posted, but if someone else is a year or more ahead and turns out to be willing to share, why reinvent or start from zero. 

0 Likes
Message 7 of 7

WCrihfield
Mentor
Mentor

I was just quickly reviewing the latest posts in this forum, saw this topic pop-up again, stepped into it, out of curiosity.  When I quickly scanned down through the original code posted above, I saw a simplistic looking custom Function (named "GetMaterialForPart") that was using some very outdated code resources, so I was just going to suggest an updated replacement for it here.  This sort of thing is common for AI generated code.

The original Function:

Private Function GetMaterialForPart(doc As Document) As String
    Try
        Return doc.ComponentDefinition.Material.Name
    Catch ex As Exception
        Return ""
    End Try
End Function

the updated one:

Private Function GetMaterialForPart(doc As Inventor.Document) As String
	Dim oPDoc As Inventor.PartDocument = TryCast(doc, Inventor.PartDocument)
	If oPDoc Is Nothing Then Return String.Empty
	Return oPDoc.ActiveMaterial.Name
End Function

The related Inventor API online help webpage describing the change in code-based resources that happened back in the 2014 version of Inventor is at the following Link:  Consistent Materials (Materials and Appearances).  We no longer access materials through the ComponentDefinition, but directly through the Document as Asset Type objects.  The old properties and methods were 'hidden' at that time, but Autodesk continued to allow their functionality in the background (for 'legacy' solutions support) while encouraging everyone to transition to using the newer resources, and instructing us not to rely on 'hidden' resources, because they may cease to exist or function at any time.  And since the only Document sub type which has an 'active' material is a part, the replacement code attempts to Cast the supplied generic Document to the more specific PartDocument Type in a way that will not throw an error, but will return 'Nothing' when the Cast operation fails.  If it was not a part, it will return an empty String.  If it was a part, it returns the name of its active material using the following two properties.

PartDocument.ActiveMaterial (Read/Write with Inventor.Asset Type value)

Asset.Name (ReadOnly String - language independent version)

Also related:  Asset.DisplayName (language dependent version)

Wesley Crihfield

EESignature

(Not an Autodesk Employee)