iLogic - iterate through named parts and assemblies and save all

iLogic - iterate through named parts and assemblies and save all

relicseekerharry
Contributor Contributor
95 Views
1 Reply
Message 1 of 2

iLogic - iterate through named parts and assemblies and save all

relicseekerharry
Contributor
Contributor

Hi all, I'm really close to finding a solution to my problem, but the last bits are evading me! 

I'm trying to make a rule that loops through a main assembly, checks each occurrence name against a list (on a hit, grab the name to save as and drawing location), recurses if it is an assembly, then saves (into the folder the top-level assembly is saved into) and replaces each component (and drawing/drawing reference) from the bottom up with the new versions until everything named has been replaced with a prefixed version in the assembly folder.

 

I've gotten it working for parts and assemblies, all drawings save and replace model views properly, but anything involving weldments complicates how things get saved and replaced as they don't follow the rules!

All the components are saved into the folder (i.e. the download folder looks right), but something isn't done in the right order as certain weldments and components within weldments reference the original non-prefixed file instead of the new prefixed replacement after running the rule, and other weldments are fine.

 

I've included the problem code and how it gets there (something in the SaveComponent() sub). Hopefully someone can make sense of this! 

 

' does not replace:
' sheet metal inside weldment inside assembly: _90_01_01 - _03
' weldment inside weldment: _00 and _01
' weldment: _1400144

Sub Main()
    ' list of components visited to ensure no double save
    Dim visitedDocs As New List(Of String)

    ' sanity check
    Dim oAsmDoc As AssemblyDocument = ThisApplication.ActiveDocument
    If oAsmDoc.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
        MessageBox.Show("You must ony run this rule from an assembly.", "Assembly only!")
        Exit Sub
    End If
	
	' prefix for saved components and folder to save to
    Dim projectName As String = iProperties.Value("Project", "Part Number")
    Dim saveFolder As String = ThisDoc.Path

    ' traverse the assembly
    Call SaveAll(oAsmDoc, visitedDocs, saveFolder, projectName)

    MessageBox.Show("All components processed and saved!", "You did it!")
End Sub

' recursive sub to take into account normal components then pattern components 
Sub SaveAll(oAsmDoc As AssemblyDocument, visitedDocs As List(Of String), saveFolder As String, projectName As String)
    If visitedDocs.Contains(LCase(oAsmDoc.FullFileName)) Then Exit Sub

    ' not a pattern element
    For Each oOcc As ComponentOccurrence In oAsmDoc.ComponentDefinition.Occurrences
        Try
			If Not visitedDocs.Contains(LCase(oOcc.Definition.Document.FullFileName)) Then
				Call ProcessOccurrence(oOcc, visitedDocs, saveFolder, projectName)
			End If
		Catch
		End Try
    Next

    ' occurrence of an element in a pattern
    For Each oPattern As OccurrencePattern In oAsmDoc.ComponentDefinition.OccurrencePatterns
        For Each oElem As OccurrencePatternElement In oPattern.OccurrencePatternElements
            For Each oPatOcc As ComponentOccurrence In oElem.Occurrences
                Try
					If Not visitedDocs.Contains(LCase(oPatOcc.Definition.Document.FullFileName)) Then
						Call ProcessOccurrence(oPatOcc, visitedDocs, saveFolder, projectName)
					End If
				Catch
				End Try
            Next
        Next
    Next
	
	' once assembly complete
	visitedDocs.Add(LCase(oAsmDoc.FullFileName))
	
End Sub

' check name of current component
' if match, send to save sub
Sub ProcessOccurrence(oOcc As ComponentOccurrence, visitedDocs As List(Of String), saveFolder As String, projectName As String)
    If oOcc.Suppressed Then Exit Sub

	Dim oDoc As Document = oOcc.Definition.Document
	If oDoc Is Nothing Then Exit Sub

	If visitedDocs.Contains(LCase(oDoc.FullFileName)) Then Exit Sub

    Dim name As String = LCase(oOcc.Name)
    Dim newName As String = ""
    Dim drawingTemplate As String = ""
		
		' template for pattern matching
    	If name = "target name" Then
            newName = "save_name"
            drawingTemplate = "drawing_path"	
		End If

    ' if found, save component
	If newName <> "" Then
    	Call SaveComponent(oDoc, oOcc, saveFolder, projectName, newName, drawingTemplate, visitedDocs)
	End If
End Sub

' save component and (hopefully) replace all occs of it with new file
Sub SaveComponent(oDoc As Document, oOcc As ComponentOccurrence, saveFolder As String, projectName As String, newName As String, drawingTemplate As String, visitedDocs As List(Of String))
    
    If visitedDocs.Contains(LCase(oDoc.FullFileName)) Then Exit Sub
    visitedDocs.Add(LCase(oDoc.FullFileName))
    
    Dim modelExt As String = ""
    Dim newModelPath As String = ""
    Dim isWeldment As Boolean = (oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject AndAlso 
                               oDoc.SubType = "{28EC8354-9024-440F-A8A2-0E0E55D635B0}")

    Select Case oDoc.DocumentType
		' simple save
        Case DocumentTypeEnum.kPartDocumentObject
            modelExt = ".ipt"
            newModelPath = System.IO.Path.Combine(saveFolder, projectName & newName & modelExt)      
            If Not System.IO.File.Exists(newModelPath) Then
                oDoc.SaveAs(newModelPath, False)
                System.Threading.Thread.Sleep(500)
            End If
        
        Case DocumentTypeEnum.kAssemblyDocumentObject
            modelExt = ".iam"
            newModelPath = System.IO.Path.Combine(saveFolder, projectName & newName & modelExt)
            
            If isWeldment Then          
                If Not System.IO.File.Exists(newModelPath) Then
                    Try
                        ' copy weldment and let it rest
                        System.IO.File.Copy(oDoc.FullFileName, newModelPath)
                        System.Threading.Thread.Sleep(1000)
                        
                        ' make list of who we have visited in the weldment already then iterate through
                        Dim weldVisited As New List(Of String)
                        Dim newAsm As AssemblyDocument = ThisApplication.Documents.Open(newModelPath, True)
                        Try
                            Call SaveAll(newAsm, weldVisited, saveFolder, projectName)
                            newAsm.Save()
                        Finally
                            newAsm.Close(True)
                        End Try
              
                        Try
                            ' replace old file with new copied file
                            oOcc.Replace(newModelPath, True)
                            
                            ' update document then give time for update to settle
                            ThisApplication.ActiveDocument.Update2(True)
                            System.Threading.Thread.Sleep(1000)
                            
                            ' weldments like to crash all of inventor so try to stabilise
                            ThisApplication.CommandManager.ControlDefinitions.Item("AppRebuildAllCmd").Execute()
                        Catch ex As Exception
                            Logger.Error("Primary replacement failed: " & ex.Message)
                            
                            ' secondary method using document reference (please)
                            Try
                                oOcc.Definition.DocumentReference.ReplaceReference(newModelPath)
                                ThisApplication.ActiveDocument.Update2(True)
                                System.Threading.Thread.Sleep(500)
                            Catch ex2 As Exception
                                Logger.Error("Fallback replacement failed: " & ex2.Message)
                            End Try
                        End Try
                    Catch ex As Exception
                        Logger.Error("Weldment processing error: " & ex.Message)
                    End Try
                End If
            Else
                ' normal assembly
                If Not System.IO.File.Exists(newModelPath) Then
                    Dim asmDoc As AssemblyDocument = CType(oDoc, AssemblyDocument)
                    asmDoc.SaveAs(newModelPath, False)
                    System.Threading.Thread.Sleep(500)
                    Call SaveAll(asmDoc, visitedDocs, saveFolder, projectName)
                End If
            End If
    End Select

    ' create drawing
    If drawingTemplate <> "" AndAlso System.IO.File.Exists(newModelPath) Then
        ' give time to let weldment behave itself
        If isWeldment Then 
            System.Threading.Thread.Sleep(1500)
            ThisApplication.ActiveDocument.Update()
        End If
        
        Try
            Dim drawingPath As String = System.IO.Path.Combine(saveFolder, projectName & newName & ".idw")
            If Not System.IO.File.Exists(drawingPath) Then
                Call SaveDrawing(drawingTemplate, drawingPath, newModelPath)
            End If
        Catch ex As Exception
            Logger.Error("Drawing creation error: " & ex.Message)
        End Try
    End If
End Sub


Sub SaveDrawing(templatePath As String, outputDrawingPath As String, modelPath As String)
    ' working - not included
		
		
	Return drawingPath
End Function

Function SelectDrawing(ByVal name As String) As String
' working - not included
Return drawingPath
End Function

 

0 Likes
Accepted solutions (1)
96 Views
1 Reply
Reply (1)
Message 2 of 2

relicseekerharry
Contributor
Contributor
Accepted solution

Found a solution that works. Passing the current component's parent document in the each sub in the recursion allows for more powerful component replacement.

 

Here's my updated saveComponent() for those that might find themselves in my predicament later on:

Sub SaveComponent(oDoc As Document, oOcc As ComponentOccurrence, saveFolder As String, projectName As String, newName As String, drawingTemplate As String, visitedDocs As List(Of String), parentAssemblyDoc As AssemblyDocument)
    If visitedDocs.Contains(LCase(oDoc.FullFileName)) Then Exit Sub
    visitedDocs.Add(LCase(oDoc.FullFileName))
    
    Dim modelExt As String = ""
    Dim newModelPath As String = ""
    Dim isWeldment As Boolean = (oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject AndAlso 
                               oDoc.SubType = "{28EC8354-9024-440F-A8A2-0E0E55D635B0}")

    ' set correct file extension
    If oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
        modelExt = ".ipt"
    ElseIf oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
        modelExt = ".iam"
    End If
    
    newModelPath = System.IO.Path.Combine(saveFolder, projectName & newName & modelExt)
    
    Select Case oDoc.DocumentType
		
		' save part (simple)
        Case DocumentTypeEnum.kPartDocumentObject
            If Not System.IO.File.Exists(newModelPath) Then 
                oDoc.SaveAs(newModelPath, False)
            End If
            
        Case DocumentTypeEnum.kAssemblyDocumentObject
            If isWeldment Then
                If Not System.IO.File.Exists(newModelPath) Then
					
                    ' copy weldment and process components
                    System.IO.File.Copy(oDoc.FullFileName, newModelPath)
                    Dim newAsm As AssemblyDocument = ThisApplication.Documents.Open(newModelPath, True)
                    Dim weldVisited As New List(Of String)
                    Try
                        SaveAll(newAsm, weldVisited, saveFolder, projectName)
                        newAsm.Save()
                    Finally
                        newAsm.Close(True)
                    End Try
                End If
            Else
                ' normal assembly save
                If Not System.IO.File.Exists(newModelPath) Then
                    oDoc.SaveAs(newModelPath, False)
                    SaveAll(CType(oDoc, AssemblyDocument), visitedDocs, saveFolder, projectName)
                End If
            End If
    End Select

    ' replace references
    If parentAssemblyDoc IsNot Nothing Then
        Try
            ' get document reference using late binding - fails sometimes
            If parentAssemblyDoc.ReferencedDocuments.Contains(oDoc.FullFileName) Then
                Dim docRef As Object = parentAssemblyDoc.ReferencedDocuments.Item(oDoc.FullFileName)
                docRef.ReplaceReference(newModelPath, True) ' update file name only
                parentAssemblyDoc.Update2(True)
            End If
        Catch ex As Exception
            Logger.Error("Reference replace failed: " & ex.Message)
            ' standard replacement (worked 100% of the time when called)
            Try
                oOcc.Replace(newModelPath, True)
                parentAssemblyDoc.Update2(True)
            Catch ex2 As Exception
                Logger.Error("Fallback replacement failed: " & ex2.Message)
            End Try
        End Try
    End If
    
    ' process drawing
	If drawingTemplate <> "" AndAlso System.IO.File.Exists(newModelPath) Then
        ' give time to let weldment behave itself
        If isWeldment Then 
            System.Threading.Thread.Sleep(1500)
            ThisApplication.ActiveDocument.Update()
        End If
        
        Try
            Dim drawingPath As String = System.IO.Path.Combine(saveFolder, projectName & newName & ".idw")
            If Not System.IO.File.Exists(drawingPath) Then
                Call SaveDrawing(drawingTemplate, drawingPath, newModelPath)
            End If
        Catch ex As Exception
            Logger.Error("Drawing creation error: " & ex.Message)
        End Try
    End If

End Sub

 

0 Likes