Macro to split multi-body part to individual part files

Edit ArticleEdit Article

Multi-body part
Multi-body part

This VBA macro allows to split active SOLIDWORKS part file into individual bodies and save each body into the separate part file preserving the bodies appearances.

  • Open multi-body part file
  • Run the macro
  • Select the output folder
  • Each body in the defeatured part is saved into individual part file as {source file name}_{body name}.sldprt

User can configure the types of bodies to export by changing the value of BODY_FILTER and VISIBLE_BODIES_ONLY constants

Const BODY_FILTER As Integer = swBodyType_e.swSheetBody 'only export surface bodies
Const VISIBLE_BODIES_ONLY As Boolean = False 'export both visible and hidden bodies

Export is perfromed via roundtrip of the solid body via STEP format. Macro will automatically set and restore required system options to produce the output

Const BODY_FILTER As Integer = swBodyType_e.swAllBodies
Const VISIBLE_BODIES_ONLY As Boolean = True

Dim swApp As SldWorks.SldWorks


Sub main()

    Set swApp = Application.SldWorks
       
    Dim swModel As SldWorks.ModelDoc2
    Set swModel = swApp.ActiveDoc
    
    If Not swModel Is Nothing Then
    
        If swModel.GetType() = swDocumentTypes_e.swDocPART Then
               
            Dim outFolder As String
            outFolder = BrowseForFolder()
            
            If outFolder <> "" Then
                SplitBodies swModel, outFolder
            End If
            
        Else
            Err.Raise vbError, "", "Active document is not a part"
        End If
    
    Else
        Err.Raise vbError, "", "Open part file"
    End If
    
End Sub

Sub SplitBodies(model As SldWorks.ModelDoc2, outFolder As String)

    Dim enable3DInterconnect As Boolean
    Dim stepExportAppearances As Boolean
    Dim stepAP As Integer
    
    swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swMultiCAD_Enable3DInterconnect, False
    enable3DInterconnect = swApp.GetUserPreferenceToggle(swUserPreferenceToggle_e.swMultiCAD_Enable3DInterconnect)
    
    stepExportAppearances = swApp.GetUserPreferenceToggle(swUserPreferenceToggle_e.swStepExportAppearances)
    swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swStepExportAppearances, True
    
    stepAP = swApp.GetUserPreferenceIntegerValue(swUserPreferenceIntegerValue_e.swStepAP)
    swApp.SetUserPreferenceIntegerValue swUserPreferenceIntegerValue_e.swStepAP, 214
                   
try_:
    On Error GoTo catch_

    Dim swPart As SldWorks.PartDoc
    
    Set swPart = model
    
    Dim vBodies As Variant
    vBodies = swPart.GetBodies2(BODY_FILTER, VISIBLE_BODIES_ONLY)
    
    Dim i As Integer
    Dim swBody As SldWorks.Body2
    
    Dim errFiles As Integer
    Dim succFiles As Integer
    
    For i = 0 To UBound(vBodies)
    
        Set swBody = vBodies(i)
        
        Dim tempOutFilePath As String
        tempOutFilePath = GetTempFilePath(".step")
        
        If TryExportBody(model, swBody, tempOutFilePath) Then
            
            Dim outFilePath As String
            outFilePath = outFolder & "\" & GetFileNameWithoutExtension(model.GetTitle()) & "_" & swBody.Name & ".sldprt"
            
            If TryImportFileAs(tempOutFilePath, outFilePath) Then
                succFiles = succFiles + 1
            Else
                errFiles = errFiles + 1
            End If
            
            Kill tempOutFilePath
        Else
            errFiles = errFiles + 1
        End If
        
    Next
    
    MsgBox "Processed: " & succFiles & " file(s). Failed: " & errFiles & " file(s)"
    
    GoTo finally_
    
catch_:
    
    MsgBox Err.Description, vbCritical

finally_:

    swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swMultiCAD_Enable3DInterconnect, enable3DInterconnect
    swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swStepExportAppearances, stepExportAppearances
    swApp.SetUserPreferenceIntegerValue swUserPreferenceIntegerValue_e.swStepAP, stepAP

End Sub

Function TryImportFileAs(srcFilePath As String, outFilePath As String) As Boolean
    
    Dim swModel As SldWorks.ModelDoc2
    
try_:
    On Error GoTo catch_
    
    Dim errs As Long
    Dim warns As Long
    
    Set swModel = swApp.LoadFile4(srcFilePath, "", Nothing, errs)
    
    If Not swModel Is Nothing Then
    
        If False <> swModel.Extension.SaveAs2(outFilePath, swSaveAsVersion_e.swSaveAsCurrentVersion, swSaveAsOptions_e.swSaveAsOptions_Silent, Nothing, "", False, errs, warns) Then
            TryImportFileAs = True
        Else
            Err.Raise vbError, "", "Failed to save file to'" & filePath & "'. Error code: " & errs
        End If
        
    Else
        Err.Raise vbError, "", "Failed to import file. Error code: " & errs
    End If
    
    GoTo finally_
catch_:
    TryImportFileAs = False
finally_:
    If Not swModel Is Nothing Then
        swApp.CloseDoc swModel.GetTitle
    End If
    
End Function

Function TryExportBody(model As SldWorks.ModelDoc2, body As SldWorks.Body2, filePath As String) As Boolean

try_:
    On Error GoTo catch_
    
    Dim swSelMgr As SldWorks.SelectionMgr
    Set swSelMgr = model.SelectionManager
    
    swSelMgr.SuspendSelectionList
    
    Dim swBodies(0) As SldWorks.Body2
    Set swBodies(0) = body
    
    If swSelMgr.AddSelectionListObjects(swBodies, Nothing) = 1 Then
                
        Dim errs As Long
        Dim warns As Long
        Dim dir As String
        
        dir = GetDirectory(filePath)
        
        CreateDirectories dir
        
        If False <> model.Extension.SaveAs2(filePath, swSaveAsVersion_e.swSaveAsCurrentVersion, swSaveAsOptions_e.swSaveAsOptions_Silent, Nothing, "", False, errs, warns) Then
            TryExportBody = True
        Else
            Err.Raise vbError, "", "Failed to export '" & body.Name & "' to '" & filePath & "'. Error code: " & errs
        End If
    Else
        Err.Raise vbError, "", "Failed to select " & body.Name
    End If

    GoTo finally_
catch_:
    TryExportBody = False
finally_:

    swSelMgr.ResumeSelectionList2 False
    
End Function

Function GetTempFilePath(ext As String) As String
    
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    Dim tempDirPath As String
    tempDirPath = fso.GetSpecialFolder(2)
    
    Dim uniqueName As String
    uniqueName = CreateObject("Scriptlet.TypeLib").GUID
    
    uniqueName = Mid(uniqueName, InStr(uniqueName, "{") + 1, InStrRev(uniqueName, "}") - InStrRev(uniqueName, "{") - 1)
    
    GetTempFilePath = tempDirPath & "\" & uniqueName & ext
    
End Function

Function GetExtension(path As String) As String
    GetExtension = Right(path, Len(path) - InStrRev(path, "."))
End Function

Function GetFileNameWithoutExtension(filePath As String) As String
    GetFileNameWithoutExtension = Mid(filePath, InStrRev(filePath, "\") + 1, InStrRev(filePath, ".") - InStrRev(filePath, "\") - 1)
End Function

Function GetDirectory(path As String)
    GetDirectory = Left(path, InStrRev(path, "\"))
End Function

Sub CreateDirectories(path As String)

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    If fso.FolderExists(path) Then
        Exit Sub
    End If

    CreateDirectories fso.GetParentFolderName(path)
    
    fso.CreateFolder path
    
End Sub

Function BrowseForFolder(Optional title As String = "Select Output Folder") As String
    
    Dim shellApp As Object
    
    Set shellApp = CreateObject("Shell.Application")
    
    Dim folder As Object
    Set folder = shellApp.BrowseForFolder(0, title, 0)
    
    If Not folder Is Nothing Then
        BrowseForFolder = folder.Self.path
    Else
        BrowseForFolder = ""
    End If
    
End Function

Product of Xarial Product of Xarial