How can I make a traverse assembly sub that I can reuse?

How can I make a traverse assembly sub that I can reuse?

JBEDsol
Collaborator Collaborator
1,097 Views
8 Replies
Message 1 of 9

How can I make a traverse assembly sub that I can reuse?

JBEDsol
Collaborator
Collaborator

So I have this code.  It tends to work ok but I'm looking to improve the efficiency of the coding for future endeavors.  I'm looking to take this method of traversing the assembly and create a sub that can be used over and over for all various traversing code I need to write.  The problem I find is that I wind up needing 100 variables to cover all the situations and things I want to do.  I'm hoping someone has a way of traversing an assembly without having to have all the rewrite code.  I imagine this is something simple but I'm just not getting it.  

 

Private Sub TraverseAssemblyPaint(Occurrences As ComponentOccurrences, Level As Integer) ' Iterate through all of the occurrence in this collection. This ' represents the occurrences at the top level of an assembly. Dim oOcc As ComponentOccurrence Dim ptdocCurrent As PartDocument Dim ptcdCurrent As PartComponentDefinition For Each oOcc In Occurrences ' Print the name of the current occurrence. If oOcc.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then ptcdCurrent = oOcc.Definition ptdocCurrent = ptcdCurrent.Document ptdocCurrent.ActiveRenderStyle = ptdocCurrent.RenderStyles.Item("Glossy - Gold") ptdocCurrent.Update() End If ' Check to see if this occurrence represents a subassembly ' and recursively call this function to traverse through it. If oOcc.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then Call TraverseAssemblyPaint(oOcc.SubOccurrences, Level + 1) End If Next End Sub Private Sub PaintFile_Click(sender As Object, e As EventArgs) Handles PaintFile.Click ' Get the active assembly. Dim oAsmDoc As AssemblyDocument oAsmDoc = appApp.ActiveDocument 'Debug.Print(oAsmDoc.DisplayName) ' Call the function that does the recursion. Call TraverseAssemblyPaint(oAsmDoc.ComponentDefinition.Occurrences, 1) End Sub

0 Likes
1,098 Views
8 Replies
Replies (8)
Message 2 of 9

yan.gauthier
Advocate
Advocate

Hi,

 

First, please use the insert code function so you code is readable 😉

 

Next, it depends what you intend to do. Are you just scanning every documents ? do you need to access every occurrences independently or would you rather access the BOM ?

 

I use these three methods depending on my actual needs.

 

Every documents in assembly : AssemblyDocument.AllReferencedDocuments

Every occurences: AssemblyDocument.ComponentDefinition.Occurrences

Access Bom: AssemblyDocument.ComponentDefinition.BOM (access the bomview you want (modelData, structured, partonly)

 

Other than that. Id say iterating through every occurrences and suboccurrences isn't that ressource intensive. 

0 Likes
Message 3 of 9

WCrihfield
Mentor
Mentor

Here's a fairly simple one I've used in the past.  In only contains one line of 'outside' code you may want to replace.  That line of code is to run another Sub defined elsewhere in the main code.

 

Sub Iterate(oOccs As ComponentOccurrencesEnumerator)
	'create new variable to enable 'Intellisense' recognition
	Dim oComps As ComponentOccurrencesEnumerator = oOccs
	Dim oCO As ComponentOccurrence
	'try to rename all comps at this level first
	For Each oCO In oComps
		'runs a Sub or Function defined elsewhere in the main code
		'my example Sub was renaming components
		RenameOcc(oCO)
	Next
	'now loop through again checking for SubOccurrences, then Iterate
	For Each oCO In oComps
		If oCO.SubOccurrences.Count > 0 Then 'it is a sub-assembly
			Iterate(oCO.SubOccurrences)
		End If
	Next
End Sub

 

 

PS.  When doing something that large, I usually recommend using a Transaction to group all the actions within into one item in the UNDO list, for simplicity.

 

If this solved your problem, or answered your question, please click ACCEPT SOLUTION.
Or, if this helped you, please click (LIKE or KUDOS) 👍.

If you want and have time, I would appreciate your Vote(s) for My IDEAS 💡or you can Explore My CONTRIBUTIONS

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 4 of 9

JBEDsol
Collaborator
Collaborator

I did use the insert code.  No idea what happened.

 

Thanks,

 

Typically (I'm not really that great of a coder) folks have some really elegant way of doing repetitive tasks that I would have never thought of.  I'm fishing for someone who's got a sleaker way of programming the traversing a model, rather than copy, tweak, repeat.  

And I'm not really looking for efficiency from a performance aspect but streamlining the coding.  So if I transverse to locate some item, or I want to recolor every item, find items and suppress links, etc. etc.  I find myself needing to completely recreate the traversing part of the code.  If I attempt to write a traverse assembly sub, I need the inputs to whatever code I need to perform as it's traversing.  Just hoping someone else has blazed that trail and has a better method.

0 Likes
Message 5 of 9

yan.gauthier
Advocate
Advocate

Like I said, it really depend of your task. If you need to act on componentOccurrence, then your approach was already good.

 

Here is an example of me using AllReferencedDocuments to look for every part which are folded SheetMetal Parts. I check if one of their custom iProperty and change its value if needed. 

 

Public Sub CheckForPliage()
' Use ActiveDocument (if it's and assembly) and select all referenced documents
' Will get every part file from referenced documents
' If part file is sheet metal type, will look if it has a flat pattern, meaning the
' Part should have the "PLIAGE" operation.
Dim invapp As Inventor.Application
Dim PrtDoc As PartDocument
Dim time1 As Single
Dim time2 As Single
Dim TotalTime As Single
Dim Properties As PropertySets
Dim Property As Property
Dim i As Integer
Dim progBar As ProgressBar
Dim Counter As Integer
Dim MainAssembly As AssemblyDocument
Dim refDoc As Object


' Start on another instance of inventor
Set invapp = ThisApplication

Counter = 0

On Error GoTo CheckForPliageErr 'Handle further error by exiting the sub
If TypeOf invapp.ActiveDocument Is AssemblyDocument Then
    Set MainAssembly = invapp.ActiveDocument
    
    time1 = timer
    
    Set progBar = invapp.CreateProgressBar(False, MainAssembly.AllReferencedDocuments.count, "PliageUpdate", False)
    
    invapp.Visible = False 'Hide inventor during routine
    

    For Each refDoc In MainAssembly.AllReferencedDocuments ' Get all referenced file in assembly
        progBar.UpdateProgress
        If TypeOf refDoc Is PartDocument Then
            Set PrtDoc = refDoc
                    If TypeOf PrtDoc.ComponentDefinition Is SheetMetalComponentDefinition Then 'Check part is sheet metal
                        If PrtDoc.ComponentDefinition.HasFlatPattern Then 'Check sheet metal has flat pattern
                            Set Properties = PrtDoc.PropertySets 'loop through properties to find user defined properties
                            For i = 1 To Properties.count
                                'Operation is stored in user defined properties when created by LoadPropModel
                                If Properties(i).DisplayName = "User Defined Properties" Then
                                    For Each Property In Properties(i)
                                        'Look for decoupe/découpe operation, if it's there, replace by PLIAGE
                                        'If a part with a flat pattern does not have decoupe/découpe, then PLIAGE
                                        'Is already there or user has not run LoadPropModel yet
                                        If LCase(Property.Expression) = "decoupe" Or LCase(Property.Expression) = "découpe" Then
                                            Property.Expression = "PLIAGE"
                                            PrtDoc.Save2 True 'Save changes
                                            Counter = Counter + 1
                                            Exit For
                                        End If
                                    Next Property
                                    Exit For
                                End If
                                
                            Next i
                            
                        End If
                    End If
            End If
    Next refDoc
    
    time2 = timer
    TotalTime = time2 - time1
    MsgBox "Check for pliage completed in " & TotalTime & vbCrLf & Counter & " file(s) changed."
Else
    MsgBox "Active File is not an Assembly"
End If

CheckForPliageErr:
If Err Then
    MsgBox "Unexpected error during CheckforPliage routine: " & Err.description, Title:="CheckForPliage"
    Err.Clear
    invapp.Visible = True
    If Not progBar Is Nothing Then
        progBar.Close
    End If
    Exit Sub
End If
invapp.Visible = True
progBar.Close
End Sub
0 Likes
Message 6 of 9

WCrihfield
Mentor
Mentor

Just dropping a link in here to another example of a recursive assembly Sub.  You may have already seen this one, since it is one of the examples posted in Inventor's online help, but here it is anyways.  It is in VBA, instead of iLogic, but it doesn't look like it would need any major changes to work in iLogic, except maybe getting rid of the Debug.Print lines.

Traverse an Assembly API Sample 

 

If this solved your problem, or answered your question, please click ACCEPT SOLUTION.
Or, if this helped you, please click (LIKE or KUDOS) 👍.

If you want and have time, I would appreciate your Vote(s) for My IDEAS 💡or you can Explore My CONTRIBUTIONS

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 7 of 9

JelteDeJong
Mentor
Mentor

Last week i wrote a blog post about finding a sheet in an idw. What i propose here is something similar. But it's a bit different approach than you might be familiar with. i propose to first create a list of all occurrences that you need and then loop over the list and do the changes (or what ever you need to do). In stead of creating a recursive function and do the changes at the moment you find the occurrences. (i will also use a recursive function but it will just generate a list.) If you have a look at the code below you will find a function called: findAllWhere()

This function takes 2 arguments

  • a list of occurrence (or an AssemblyDocument because the function is overloaded)
  • a test function (in the example below this is the function isPart() )

And will return a list of all occurrences that match the conditions specified in the "other/delegate function".

Being able to use a "test" functions makes the findAllWhere() function very flexible. here we use the test function to check if each occurrence is a part, but you could use it to check all sort of things. The onlything you should know is that the test function needs to take a occurrence 1 as argument and should return a boolean. 

Sub Main()
    Dim doc As AssemblyDocument = ThisDoc.Document
    Dim lisOfParts As IEnumerable(Of ComponentOccurrence) = findAllWhere(doc, AddressOf isPart)

    colorOcc(lisOfParts)
    doc.Update()
End Sub

'Function that checks if an occurnce is a part
Public Function isPart(occ As ComponentOccurrence) As Boolean
    Return occ.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject
End Function

'sub to color all parts in a list.
Public Sub colorOcc(list As IEnumerable(Of ComponentOccurrence))
    For Each occ As ComponentOccurrence In list
        Dim ptcdCurrent As ComponentDefinition = occ.Definition
        Dim ptdocCurrent As PartDocument = ptcdCurrent.Document
        ptdocCurrent.ActiveRenderStyle = ptdocCurrent.RenderStyles.Item("Gunmetal")
        ptdocCurrent.Update()
    Next
End Sub


'this is the function where all the magic happens and 
'that youcan use to find occurences in all sortsof ways.
Public Function findAllWhere(occs As IEnumerable(Of ComponentOccurrence), predicate As Func(Of ComponentOccurrence, Boolean)) As IEnumerable(Of ComponentOccurrence)
    Dim list As IEnumerable(Of ComponentOccurrence) = occs.Where(predicate)
    Dim assemblyList As IEnumerable(Of ComponentOccurrence) = occs.
        Where(Function(o) o.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject)

    For Each assOcc As ComponentOccurrence In assemblyList
        Dim assDoc As AssemblyDocument = assOcc.ReferencedDocumentDescriptor.ReferencedDocument
        Dim listToAdd As IEnumerable(Of ComponentOccurrence) = findAllWhere(assDoc, predicate)
        list = list.Concat(listToAdd)
    Next
    Return list
End Function
'overload function that does the casting that is needed
'this function will allow you use the default api 
'ComponentOccurrences In the first place
Public Function findAllWhere(doc As AssemblyDocument, predicate As Func(Of ComponentOccurrence, Boolean)) As IEnumerable(Of ComponentOccurrence)
    Dim occurrences As ComponentOccurrences = doc.ComponentDefinition.Occurrences
	Return findAllWhere(occurrences.Cast(Of ComponentOccurrence), predicate)
End Function

Just as an disclaimer 😉 I liked the challenge to improve on code that we all use over and over again. But remember that this is my first brain wave and its late. There for i didn't test this code much.  Let me know if it works for you and what you think!

 

 

 

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

Message 8 of 9

Curtis_Waguespack
Consultant
Consultant

@JelteDeJong, that's good stuff!

 

One thing to add to it, is to check for virtual components:

 

'this is the function where all the magic happens and 
'that you can use to find occurrences in all sorts of ways.
Public Function findAllWhere(occs As IEnumerable(Of ComponentOccurrence), predicate As Func(Of ComponentOccurrence, Boolean)) As IEnumerable(Of ComponentOccurrence)
    Dim list As IEnumerable(Of ComponentOccurrence) = occs.Where(predicate)
    Dim assemblyList As IEnumerable(Of ComponentOccurrence) = occs.
        Where(Function(o) o.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject)

    For Each assOcc As ComponentOccurrence In assemblyList
	If TypeOf assOcc.Definition Is VirtualComponentDefinition Then Continue For
        Dim assDoc As AssemblyDocument = assOcc.ReferencedDocumentDescriptor.ReferencedDocument
        Dim listToAdd As IEnumerable(Of ComponentOccurrence) = findAllWhere(assDoc, predicate)
        list = list.Concat(listToAdd)
    Next
    Return list
End Function

 

EESignature

Message 9 of 9

JelteDeJong
Mentor
Mentor

Thanks @Curtis_Waguespack that is an good improvement.

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

0 Likes