thank you for fast respond. i did figure out how to add custom prop but still have problem to add Description of part. in my case i do not need material thickness since is in description of material. my order is material part number (description) and TTL . Description is for me very important but struggling for hours to fix. here is rule i fixed for my need.

AddReference "System.Drawing"
AddReference "System.Xml"
AddReference "System.Windows.Forms"
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Xml.Serialization
Imports System.IO
Imports TextBox = System.Windows.Forms.TextBox
Imports Point = System.Drawing.Point
Imports Color = System.Drawing.Color
Imports Path = System.IO.Path
Imports File = System.IO.File
Imports Environment = System.Environment
' Configuration class for use during export
Public Class Configuration
Public TargetDirectory As String
Public UseComponentFolder As Boolean
Public EnableLogging As Boolean
Public LogFileName As String
Public FileNameFormat As String
Public DXFOptions As String
Public SortByMaterial As Boolean
Public SortByThickness As Boolean
Public CleanFileNames As Boolean
End Class
' Serializable class to store user settings
<Serializable()> _
Public Class UserSettings
Public Property TargetDirectory As String = "C:\DXF"
Public Property UseComponentFolder As Boolean = False
Public Property EnableLogging As Boolean = False
Public Property FileNameFormat As String = "{material} {partNumber} TTL{TTL}" ' Added space and "TTL" prefix
Public Property DXFOptions As String = "FLAT PATTERN DXF?AcadVersion=R12&RebaseGeometry=True&MergeProfilesIntoPolyline=True&SimplifySpline=True&InteriorProfilesLayer=IV_INTERIOR_PROFILES&InvisibleLayers=IV_TANGENT;IV_BEND;IV_BEND_DOWN;IV_TOOL_CENTER_DOWN;IV_ARC_CENTERS;IV_FEATURE_PROFILES;IV_FEATURE_PROFILES_DOWN;IV_UNCONSUMED_SKETCHES;IV_ROLL_TANGENT;IV_ROLL&SplineToleranceDouble=0.01"
Public Property SortByMaterial As Boolean = False
Public Property SortByThickness As Boolean = False
Public Property CleanFileNames As Boolean = True
End Class
' Class for managing DXF export settings
Public Class SettingsManager
Private Shared ReadOnly SettingsFileName As String = "DXFExportSettings.xml"
Public Shared Function GetSettingsDirectory() As String
Dim appDataPath As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Dim settingsPath As String = Path.Combine(appDataPath, "Autodesk", "Inventor", "DXFExport")
If Not Directory.Exists(settingsPath) Then
Try
Directory.CreateDirectory(settingsPath)
Catch ex As Exception
MessageBox.Show("Could not create settings directory: " & ex.Message & vbCrLf &
"Using default path: " & appDataPath, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Return appDataPath
End Try
End If
Return settingsPath
End Function
Public Shared Function GetSettingsFilePath() As String
Return Path.Combine(GetSettingsDirectory(), SettingsFileName)
End Function
Public Shared Sub SaveSettings(settings As UserSettings)
Try
Dim filePath As String = GetSettingsFilePath()
MessageBox.Show("Saving to: " & filePath) ' Debug message
Dim serializer As New XmlSerializer(GetType(UserSettings))
Using writer As New StreamWriter(filePath)
serializer.Serialize(writer, settings)
End Using
Catch ex As Exception
MessageBox.Show("Could not save settings: " & ex.Message,
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Try
End Sub
Public Shared Function LoadSettings() As UserSettings
Dim filePath As String = GetSettingsFilePath()
If Not File.Exists(filePath) Then
Return New UserSettings()
End If
Try
Dim serializer As New XmlSerializer(GetType(UserSettings))
Using reader As New StreamReader(filePath)
Return DirectCast(serializer.Deserialize(reader), UserSettings)
End Using
Catch ex As Exception
MessageBox.Show("Could not load settings: " & ex.Message & vbCrLf &
"Using default settings instead.", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
Return New UserSettings()
End Try
End Function
End Class
' Settings Form Class
Public Class SettingsForm
Inherits System.Windows.Forms.Form
Private WithEvents btnOK As Button
Private WithEvents btnCancel As Button
Private WithEvents btnBrowse As Button
Private WithEvents radStaticFolder As RadioButton
Private WithEvents radComponentFolder As RadioButton
Private txtTargetDir As TextBox
Private chkLogging As CheckBox
Private txtFileNameFormat As TextBox
Private lblFileNameHelp As Label
Private chkSortByMaterial As CheckBox
Private chkSortByThickness As CheckBox
Private chkCleanFileNames As CheckBox
Public Property TargetDirectory As String
Public Property UseComponentFolder As Boolean
Public Property EnableLogging As Boolean
Public Property FileNameFormat As String
Public Property DXFOptions As String
Public Property SortByMaterial As Boolean
Public Property SortByThickness As Boolean
Public Property CleanFileNames As Boolean
Private Const FORM_PADDING As Integer = 12
Private Const GROUP_PADDING As Integer = 20
Private Const LABEL_HEIGHT As Integer = 24
Private Const CONTROL_HEIGHT As Integer = 28
Private Const BUTTON_WIDTH As Integer = 100
Private Const BUTTON_HEIGHT As Integer = 36
Private Const BROWSE_BUTTON_WIDTH As Integer = 50
Public Sub New()
Me.Text = "DXF Export Settings"
Me.FormBorderStyle = FormBorderStyle.FixedDialog
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.StartPosition = FormStartPosition.CenterScreen
Me.ClientSize = New Size(540, 400)
Me.Font = New Font("Segoe UI", 9.5F)
Me.Padding = New Padding(FORM_PADDING)
Dim gbExportLocation As New GroupBox()
gbExportLocation.Text = "Export Location"
gbExportLocation.Location = New Point(FORM_PADDING, FORM_PADDING)
gbExportLocation.Width = Me.ClientSize.Width - (FORM_PADDING * 2)
gbExportLocation.Height = 110
gbExportLocation.Padding = New Padding(GROUP_PADDING)
radStaticFolder = New RadioButton()
radStaticFolder.Text = "Static Folder:"
radStaticFolder.Location = New Point(GROUP_PADDING, 24)
radStaticFolder.AutoSize = True
radStaticFolder.Checked = True
txtTargetDir = New TextBox()
txtTargetDir.Location = New Point(GROUP_PADDING + 120, 22)
txtTargetDir.Size = New Size(gbExportLocation.Width - 220, CONTROL_HEIGHT)
txtTargetDir.Anchor = AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
btnBrowse = New Button()
btnBrowse.Text = "..."
btnBrowse.Location = New Point(gbExportLocation.Width - BROWSE_BUTTON_WIDTH - GROUP_PADDING, 21)
btnBrowse.Size = New Size(BROWSE_BUTTON_WIDTH, CONTROL_HEIGHT)
btnBrowse.Anchor = AnchorStyles.Right Or AnchorStyles.Top
radComponentFolder = New RadioButton()
radComponentFolder.Text = "Main Component Folder"
radComponentFolder.Location = New Point(GROUP_PADDING, 60)
radComponentFolder.AutoSize = True
gbExportLocation.Controls.AddRange({radStaticFolder, radComponentFolder, txtTargetDir, btnBrowse})
Dim gbFileOptions As New GroupBox()
gbFileOptions.Text = "File Options"
gbFileOptions.Location = New Point(FORM_PADDING, gbExportLocation.Bottom + FORM_PADDING)
gbFileOptions.Width = Me.ClientSize.Width - (FORM_PADDING * 2)
gbFileOptions.Height = 200
gbFileOptions.Padding = New Padding(GROUP_PADDING)
chkLogging = New CheckBox()
chkLogging.Text = "Enable Logging"
chkLogging.Location = New Point(GROUP_PADDING, 25)
chkLogging.AutoSize = True
Dim lblFileName As New Label()
lblFileName.Text = "File Name Format:"
lblFileName.Location = New Point(GROUP_PADDING, 60)
lblFileName.AutoSize = True
txtFileNameFormat = New TextBox()
txtFileNameFormat.Location = New Point(GROUP_PADDING + 120, 58)
txtFileNameFormat.Size = New Size(gbFileOptions.Width - 160, CONTROL_HEIGHT)
txtFileNameFormat.Anchor = AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
lblFileNameHelp = New Label()
lblFileNameHelp.Text = "Available: {partNumber}, {material}, {TTL} (e.g., {material} {partNumber} TTL{TTL})"
lblFileNameHelp.Location = New Point(GROUP_PADDING + 120, 88)
lblFileNameHelp.AutoSize = True
lblFileNameHelp.ForeColor = Color.DarkGray
Dim gbSortOptions As New GroupBox()
gbSortOptions.Text = "Folder Sorting"
gbSortOptions.Location = New Point(GROUP_PADDING, 120)
gbSortOptions.Width = gbFileOptions.Width - (GROUP_PADDING * 2)
gbSortOptions.Height = 90
gbSortOptions.Padding = New Padding(10)
chkSortByMaterial = New CheckBox()
chkSortByMaterial.Text = "Sort by Material"
chkSortByMaterial.Location = New Point(15, 25)
chkSortByMaterial.AutoSize = True
chkSortByThickness = New CheckBox()
chkSortByThickness.Text = "Sort by Thickness"
chkSortByThickness.Location = New Point(15, 55)
chkSortByThickness.AutoSize = True
gbSortOptions.Controls.AddRange({chkSortByMaterial, chkSortByThickness})
chkCleanFileNames = New CheckBox()
chkCleanFileNames.Text = "Clean Filename (Replace Spaces and Punctuation)"
chkCleanFileNames.Location = New Point(GROUP_PADDING, 155)
chkCleanFileNames.AutoSize = True
chkCleanFileNames.Checked = True
gbFileOptions.Controls.AddRange({chkLogging, lblFileName, txtFileNameFormat, lblFileNameHelp, gbSortOptions, chkCleanFileNames})
Dim buttonPanel As New Panel()
buttonPanel.Width = Me.ClientSize.Width - (FORM_PADDING * 2)
buttonPanel.Height = BUTTON_HEIGHT + 10
buttonPanel.Location = New Point(FORM_PADDING, gbFileOptions.Bottom + FORM_PADDING)
btnCancel = New Button()
btnCancel.Text = "Cancel"
btnCancel.Location = New Point(buttonPanel.Width - BUTTON_WIDTH - 5, 0)
btnCancel.Size = New Size(BUTTON_WIDTH, BUTTON_HEIGHT)
btnCancel.DialogResult = DialogResult.Cancel
btnCancel.Anchor = AnchorStyles.Right
btnOK = New Button()
btnOK.Text = "OK"
btnOK.Location = New Point(buttonPanel.Width - (BUTTON_WIDTH * 2) - 15, 0)
btnOK.Size = New Size(BUTTON_WIDTH, BUTTON_HEIGHT)
btnOK.DialogResult = DialogResult.OK
btnOK.Anchor = AnchorStyles.Right
buttonPanel.Controls.AddRange({btnOK, btnCancel})
Me.Controls.AddRange({gbExportLocation, gbFileOptions, buttonPanel})
Dim toolTip As New ToolTip()
toolTip.SetToolTip(txtTargetDir, "Directory where DXF files will be saved")
toolTip.SetToolTip(btnBrowse, "Browse for target directory")
toolTip.SetToolTip(radStaticFolder, "Always export to the specified folder")
toolTip.SetToolTip(radComponentFolder, "Export to the folder containing the main component")
toolTip.SetToolTip(chkLogging, "Create a log file with detailed information about the export process")
toolTip.SetToolTip(txtFileNameFormat, "Format template for exported DXF filenames")
toolTip.SetToolTip(chkSortByMaterial, "Create subfolders for each material type")
toolTip.SetToolTip(chkSortByThickness, "Create subfolders for each thickness value")
toolTip.SetToolTip(chkCleanFileNames, "Replace spaces and punctuation with underscores in filenames and folder names")
Me.AcceptButton = btnOK
Me.CancelButton = btnCancel
LoadSavedSettings()
Me.ClientSize = New Size(Me.ClientSize.Width, buttonPanel.Bottom + FORM_PADDING)
End Sub
Private Sub LoadSavedSettings()
Try
Dim settings As UserSettings = SettingsManager.LoadSettings()
txtTargetDir.Text = settings.TargetDirectory
radComponentFolder.Checked = settings.UseComponentFolder
radStaticFolder.Checked = Not settings.UseComponentFolder
chkLogging.Checked = settings.EnableLogging
txtFileNameFormat.Text = settings.FileNameFormat
chkSortByMaterial.Checked = settings.SortByMaterial
chkSortByThickness.Checked = settings.SortByThickness
chkCleanFileNames.Checked = settings.CleanFileNames
DXFOptions = settings.DXFOptions
txtTargetDir.Enabled = Not settings.UseComponentFolder
btnBrowse.Enabled = Not settings.UseComponentFolder
Catch ex As Exception
MessageBox.Show("Could not load saved settings. Using default settings.",
"Settings Error", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Try
End Sub
Private Sub radStaticFolder_CheckedChanged(sender As Object, e As EventArgs) Handles radStaticFolder.CheckedChanged
If txtTargetDir IsNot Nothing AndAlso btnBrowse IsNot Nothing Then
txtTargetDir.Enabled = radStaticFolder.Checked
btnBrowse.Enabled = radStaticFolder.Checked
End If
End Sub
Private Sub radComponentFolder_CheckedChanged(sender As Object, e As EventArgs) Handles radComponentFolder.CheckedChanged
If txtTargetDir IsNot Nothing AndAlso btnBrowse IsNot Nothing Then
txtTargetDir.Enabled = Not radComponentFolder.Checked
btnBrowse.Enabled = Not radComponentFolder.Checked
End If
End Sub
Private Sub btnBrowse_Click(sender As Object, e As EventArgs) Handles btnBrowse.Click
Dim folderBrowser As New FolderBrowserDialog()
folderBrowser.Description = "Select Target Directory for DXF Export"
folderBrowser.ShowNewFolderButton = True
If Not String.IsNullOrEmpty(txtTargetDir.Text) AndAlso System.IO.Directory.Exists(txtTargetDir.Text) Then
folderBrowser.SelectedPath = txtTargetDir.Text
End If
If folderBrowser.ShowDialog() = DialogResult.OK Then
txtTargetDir.Text = folderBrowser.SelectedPath
End If
End Sub
Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
If radStaticFolder.Checked AndAlso String.IsNullOrEmpty(txtTargetDir.Text) Then
MessageBox.Show("Target directory cannot be empty when using static folder option.",
"Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
txtTargetDir.Focus()
Return
End If
If String.IsNullOrEmpty(txtFileNameFormat.Text) Then
MessageBox.Show("File name format cannot be empty.", "Validation Error",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtFileNameFormat.Focus()
Return
End If
SaveFormSettingsToProperties()
SaveCurrentSettingsToXml(True)
Me.DialogResult = DialogResult.OK
Me.Close()
End Sub
Private Sub SaveFormSettingsToProperties()
UseComponentFolder = radComponentFolder.Checked
TargetDirectory = txtTargetDir.Text
EnableLogging = chkLogging.Checked
FileNameFormat = txtFileNameFormat.Text
SortByMaterial = chkSortByMaterial.Checked
SortByThickness = chkSortByThickness.Checked
CleanFileNames = chkCleanFileNames.Checked
End Sub
Private Sub SaveCurrentSettingsToXml(showErrors As Boolean)
Try
Dim settings As New UserSettings()
settings.TargetDirectory = txtTargetDir.Text
settings.UseComponentFolder = radComponentFolder.Checked
settings.EnableLogging = chkLogging.Checked
settings.FileNameFormat = txtFileNameFormat.Text
settings.DXFOptions = DXFOptions
settings.SortByMaterial = chkSortByMaterial.Checked
settings.SortByThickness = chkSortByThickness.Checked
settings.CleanFileNames = chkCleanFileNames.Checked
SettingsManager.SaveSettings(settings)
Catch ex As Exception
If showErrors Then
MessageBox.Show("Could not save settings: " & ex.Message,
"Settings Error", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End Try
End Sub
Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
SaveCurrentSettingsToXml(False)
Me.DialogResult = DialogResult.Cancel
Me.Close()
End Sub
End Class
' Main method start
Sub Main()
Dim settingsForm As New SettingsForm
If settingsForm.ShowDialog() <> DialogResult.OK Then
Exit Sub
End If
Dim doc As Inventor.Document = ThisApplication.ActiveDocument
If doc Is Nothing Then
MessageBox.Show("No document is open.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If
Dim config As New Configuration
config.UseComponentFolder = settingsForm.UseComponentFolder
config.SortByMaterial = settingsForm.SortByMaterial
config.SortByThickness = settingsForm.SortByThickness
config.CleanFileNames = settingsForm.CleanFileNames
If config.UseComponentFolder Then
Dim docPath As String = ""
Try
docPath = System.IO.Path.GetDirectoryName(doc.FullFileName)
If String.IsNullOrEmpty(docPath) OrElse Not System.IO.Directory.Exists(docPath) Then
Throw New Exception("Cannot access document folder")
End If
config.TargetDirectory = docPath
Catch ex As Exception
MessageBox.Show("Could not determine the component folder: " & ex.Message & vbCrLf &
"Falling back to default folder.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
config.TargetDirectory = settingsForm.TargetDirectory
End Try
Else
config.TargetDirectory = settingsForm.TargetDirectory
End If
config.EnableLogging = settingsForm.EnableLogging
config.LogFileName = "ExportLog.txt"
config.FileNameFormat = settingsForm.FileNameFormat
config.DXFOptions = settingsForm.DXFOptions
If Not System.IO.Directory.Exists(config.TargetDirectory) Then
Try
System.IO.Directory.CreateDirectory(config.TargetDirectory)
Catch ex As Exception
MessageBox.Show("Could not create the target directory: " & ex.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End Try
End If
Dim logFilePath As String = System.IO.Path.Combine(config.TargetDirectory, config.LogFileName)
If config.EnableLogging Then
Try
Dim logHeader As String = "DXF Export Log" & vbCrLf & _
"Started: " & DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") & vbCrLf & _
"Target Directory: " & config.TargetDirectory & vbCrLf & _
"Export Options: " & config.DXFOptions & vbCrLf & _
"Sort by Material: " & config.SortByMaterial & vbCrLf & _
"Sort by Thickness: " & config.SortByThickness & vbCrLf & _
"Clean Filenames: " & config.CleanFileNames & vbCrLf & vbCrLf
System.IO.File.WriteAllText(logFilePath, logHeader)
Catch ex As Exception
MessageBox.Show("Could not create log file: " & ex.Message, "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
config.EnableLogging = False
End Try
End If
If doc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
Dim asmDoc As AssemblyDocument = CType(doc, AssemblyDocument)
Dim sheetMetalParts As New Dictionary(Of String, Integer)
ProcessComponentOccurrences(asmDoc.ComponentDefinition.Occurrences, sheetMetalParts, logFilePath, config)
Dim progressBar As Inventor.ProgressBar = ThisApplication.CreateProgressBar(False, sheetMetalParts.Count, "Exporting DXF Files")
Dim currentStep As Integer = 0
ExportDXFFiles(sheetMetalParts, config.TargetDirectory, logFilePath, config, progressBar, currentStep)
progressBar.Close()
ElseIf doc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
Dim partDoc As PartDocument = CType(doc, PartDocument)
If partDoc.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then
Dim progressBar As Inventor.ProgressBar = ThisApplication.CreateProgressBar(False, 1, "Exporting DXF File")
Dim currentStep As Integer = 0
ExportSinglePartDXF(partDoc, config.TargetDirectory, logFilePath, config, progressBar, currentStep)
progressBar.Close()
Else
If config.EnableLogging Then LogError(logFilePath, "The active document is not a sheet metal part.")
MessageBox.Show("The active document is not a sheet metal part.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Else
If config.EnableLogging Then LogError(logFilePath, "The active document is neither an assembly nor a sheet metal part.")
MessageBox.Show("The active document is neither an assembly nor a sheet metal part.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
MessageBox.Show("DXF export completed to folder: " & vbCrLf & config.TargetDirectory, "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Sub ProcessComponentOccurrences(occurrences As ComponentOccurrences, sheetMetalParts As Dictionary(Of String, Integer), logFilePath As String, config As Configuration)
For Each occ As ComponentOccurrence In occurrences
Try
If occ.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
Dim partDoc As PartDocument = CType(occ.Definition.Document, PartDocument)
If partDoc.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then
Dim smCompDef As SheetMetalComponentDefinition = CType(partDoc.ComponentDefinition, SheetMetalComponentDefinition)
If smCompDef.HasFlatPattern Then
Dim partNumber As String = partDoc.PropertySets.Item("Design Tracking Properties").Item("Part Number").Value.ToString()
Dim ttl As Integer = 1
Try
Dim customProps As PropertySet = partDoc.PropertySets.Item("Inventor User Defined Properties")
Dim ttlProp As Inventor.Property = customProps.Item("TTL")
ttl = CInt(ttlProp.Value)
Catch
If config.EnableLogging Then LogError(logFilePath, "TTL property not found for part: " & partNumber & ", using default TTL=1")
End Try
If sheetMetalParts.ContainsKey(partNumber) Then
sheetMetalParts(partNumber) += ttl
Else
sheetMetalParts.Add(partNumber, ttl)
End If
Else
If config.EnableLogging Then LogError(logFilePath, "Skipping DXF file for: " & partDoc.FullFileName & " - Flat Pattern Missing")
End If
End If
ElseIf occ.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
ProcessComponentOccurrences(occ.SubOccurrences, sheetMetalParts, logFilePath, config)
End If
Catch ex As Exception
If config.EnableLogging Then LogError(logFilePath, "Error processing occurrence: " & occ.Name & " - " & ex.Message)
End Try
Next
End Sub
Function GetExportDirectory(baseDir As String, material As String, thickness As String, config As Configuration) As String
Dim exportDir As String = baseDir
If config.SortByMaterial AndAlso Not String.IsNullOrEmpty(material) AndAlso material <> "Unknown" Then
exportDir = Path.Combine(exportDir, material)
If config.SortByThickness AndAlso Not String.IsNullOrEmpty(thickness) AndAlso thickness <> "Unknown" Then
exportDir = Path.Combine(exportDir, thickness)
End If
ElseIf config.SortByThickness AndAlso Not String.IsNullOrEmpty(thickness) AndAlso thickness <> "Unknown" Then
exportDir = Path.Combine(exportDir, thickness)
End If
If Not Directory.Exists(exportDir) Then
Try
Directory.CreateDirectory(exportDir)
Catch ex As Exception
Return baseDir
End Try
End If
Return exportDir
End Function
Sub ExportDXFFiles(sheetMetalParts As Dictionary(Of String, Integer), targetDir As String, logFilePath As String, config As Configuration, progressBar As Inventor.ProgressBar, ByRef currentStep As Integer)
For Each partNumber As String In sheetMetalParts.Keys
currentStep += 1
Dim ttl As Integer = sheetMetalParts(partNumber)
Dim partDoc As PartDocument = Nothing
Try
partDoc = OpenPartDocument(partNumber)
If partDoc Is Nothing Then
Throw New Exception("Part file not found or couldn't be opened")
End If
Dim material As String = GetMaterial(partDoc, config.CleanFileNames)
Dim thickness As String = GetThickness(partDoc, 2)
Dim exportDir As String = GetExportDirectory(targetDir, material, thickness, config)
Dim fileName As String = FormatFileName(config.FileNameFormat, partNumber, material, ttl)
Dim filePath As String = Path.Combine(exportDir, fileName & ".dxf")
If config.EnableLogging Then
LogError(logFilePath, "Processing part: " & partNumber)
LogError(logFilePath, "Export directory: " & exportDir)
LogError(logFilePath, "File path: " & filePath)
End If
If Not IsValidPath(filePath) Then
If config.EnableLogging Then LogError(logFilePath, "Invalid file path: " & filePath)
Continue For
End If
If config.EnableLogging Then LogError(logFilePath, "Opened document: " & partDoc.FullFileName)
Dim smCompDef As SheetMetalComponentDefinition = CType(partDoc.ComponentDefinition, SheetMetalComponentDefinition)
If smCompDef.HasFlatPattern Then
Dim flatPattern As FlatPattern = smCompDef.FlatPattern
Dim oDataIO As DataIO = flatPattern.DataIO
If config.EnableLogging Then LogError(logFilePath, "Prepared DataIO for: " & partDoc.FullFileName)
Try
oDataIO.WriteDataToFile(config.DXFOptions, filePath)
If config.EnableLogging Then LogError(logFilePath, "Exported DXF for: " & partDoc.FullFileName & " to " & filePath)
Catch ex As Exception
If config.EnableLogging Then LogError(logFilePath, "Error exporting DXF for: " & partDoc.FullFileName & " - " & ex.Message)
End Try
Else
If config.EnableLogging Then LogError(logFilePath, "Skipping DXF file for: " & partDoc.FullFileName & " - Flat Pattern Missing")
End If
Catch ex As Exception
If config.EnableLogging Then LogError(logFilePath, "Error processing part: " & partNumber & " - " & ex.Message)
Finally
If partDoc IsNot Nothing Then
partDoc.Close(False)
If config.EnableLogging Then LogError(logFilePath, "Closed document: " & partDoc.FullFileName)
End If
Dim progressPercent As Integer = CInt((currentStep / sheetMetalParts.Count) * 100)
progressBar.Message = "Exporting: " & partNumber & " (" & progressPercent & "%)"
progressBar.UpdateProgress()
End Try
Next
End Sub
Sub ExportSinglePartDXF(partDoc As PartDocument, targetDir As String, logFilePath As String, config As Configuration, progressBar As Inventor.ProgressBar, ByRef currentStep As Integer)
currentStep += 1
Dim partNumber As String = partDoc.PropertySets.Item("Design Tracking Properties").Item("Part Number").Value.ToString()
Dim material As String = GetMaterial(partDoc, config.CleanFileNames)
Dim thickness As String = GetThickness(partDoc, 2)
Dim ttl As Integer = 1
Try
Dim customProps As PropertySet = partDoc.PropertySets.Item("Inventor User Defined Properties")
Dim ttlProp As Inventor.Property = customProps.Item("TTL")
ttl = CInt(ttlProp.Value)
Catch
If config.EnableLogging Then LogError(logFilePath, "TTL property not found for part: " & partNumber & ", using default TTL=1")
End Try
Dim exportDir As String = GetExportDirectory(targetDir, material, thickness, config)
Dim fileName As String = FormatFileName(config.FileNameFormat, partNumber, material, ttl)
Dim filePath As String = Path.Combine(exportDir, fileName & ".dxf")
If config.EnableLogging Then
LogError(logFilePath, "Processing part: " & partNumber)
LogError(logFilePath, "Export directory: " & exportDir)
LogError(logFilePath, "File path: " & filePath)
End If
If Not IsValidPath(filePath) Then
If config.EnableLogging Then LogError(logFilePath, "Invalid file path: " & filePath)
Exit Sub
End If
Try
Dim smCompDef As SheetMetalComponentDefinition = CType(partDoc.ComponentDefinition, SheetMetalComponentDefinition)
If smCompDef.HasFlatPattern Then
Dim flatPattern As FlatPattern = smCompDef.FlatPattern
Dim oDataIO As DataIO = flatPattern.DataIO
If config.EnableLogging Then LogError(logFilePath, "Prepared DataIO for: " & partDoc.FullFileName)
Try
oDataIO.WriteDataToFile(config.DXFOptions, filePath)
If config.EnableLogging Then LogError(logFilePath, "Exported DXF for: " & partDoc.FullFileName & " to " & filePath)
Catch ex As Exception
If config.EnableLogging Then LogError(logFilePath, "Error exporting DXF for: " & partDoc.FullFileName & " - " & ex.Message)
End Try
Else
If config.EnableLogging Then LogError(logFilePath, "Skipping DXF file for: " & partDoc.FullFileName & " - Flat Pattern Missing")
End If
Catch ex As Exception
If config.EnableLogging Then LogError(logFilePath, "Error processing part: " & partNumber & " - " & ex.Message)
Finally
progressBar.Message = "Exporting: " & partNumber & " (100%)"
progressBar.UpdateProgress()
End Try
End Sub
Function FormatFileName(format As String, partNumber As String, material As String, ttl As Integer) As String
Dim fileName As String = format
fileName = fileName.Replace("{partNumber}", partNumber)
fileName = fileName.Replace("{material}", material)
fileName = fileName.Replace("{description}", description)
fileName = fileName.Replace("{TTL}", ttl.ToString())
Return fileName
End Function
Function OpenPartDocument(partNumber As String) As PartDocument
Dim app As Inventor.Application = ThisApplication
Dim docs As Documents = app.Documents
Dim projectManager As DesignProjectManager = app.DesignProjectManager
Dim activeProject As DesignProject = projectManager.ActiveDesignProject
For Each doc As Document In docs
If TypeOf doc Is PartDocument AndAlso doc.PropertySets.Item("Design Tracking Properties").Item("Part Number").Value.ToString() = partNumber Then
Return CType(doc, PartDocument)
End If
Next
Dim fullFileName As String = activeProject.FindFiles(partNumber & ".ipt").Item(1)
If Not String.IsNullOrEmpty(fullFileName) Then
Return CType(docs.Open(fullFileName), PartDocument)
End If
Return Nothing
End Function
Function IsValidPath(path As String) As Boolean
Dim isValid As Boolean = True
Try
Dim fileInfo As New System.IO.FileInfo(path)
Catch ex As Exception
isValid = False
End Try
Return isValid
End Function
Sub LogError(logFilePath As String, message As String)
System.IO.File.AppendAllText(logFilePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") & " - " & message & vbCrLf)
End Sub
Function GetMaterial(partDoc As PartDocument, cleanNames As Boolean) As String
Try
Dim material As String = partDoc.PropertySets.Item("Design Tracking Properties").Item("Material").Value.ToString()
If cleanNames Then
Dim cleanedMaterial As String = material
Dim punctuationChars() As Char = {" ", ",", ".", ";", ":", "'", """", "!", "?", "(", ")", "[", "]", "{", "}", "/", "\", "-", "+", "=", "*", "&", "^", "%", "$", "#", "@"}
For Each c As Char In punctuationChars
cleanedMaterial = cleanedMaterial.Replace(c, "_"c)
Next
While cleanedMaterial.Contains("__")
cleanedMaterial = cleanedMaterial.Replace("__", "_")
End While
cleanedMaterial = cleanedMaterial.Trim("_"c)
Return cleanedMaterial
Else
Return material
End If
Catch
Return "Unknown"
End Try
End Function
Function GetThickness(partDoc As PartDocument, rounding As Integer) As String
Try
Dim smCompDef As SheetMetalComponentDefinition = CType(partDoc.ComponentDefinition, SheetMetalComponentDefinition)
Dim thickness As Double = smCompDef.Thickness.Value
Dim thicknessMM As Double = thickness * 10
Dim thicknessFormatted As String = Math.Round(thicknessMM, rounding).ToString() & "mm"
Return thicknessFormatted
Catch
Return "Unknown"
End Try
End Function