Last week some one on the “Autodesk Inventor customization” forum asked the following:

“I have this code.  It tends to work ok but I'm looking to improve the efficiency of the coding for future endeavours.  I'm want to make a method for traversing the assembly and sub's so that it can be used over and over for all various traversing code I need to write.”

He did create a recursive function that look like this:

Private Sub recursiveSearch(doc As AssemblyDocument)
    Dim Occurrences As ComponentOccurrences
    For Each occ As ComponentOccurrence In Occurrences
        ' Print the name Of the current occurrence.
        If occ.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
             'Do stuff with the found Occurrence
        End If
        If occ.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
            Call recursiveSearch(occ.Definition.Document)
        End If
    Next
End Sub

I have to admit this is how I would solve this, if I need to do something to an occurrence of an (sub)assembly. But as he wrote you can’t reuse this code. For example: The code above will only find part occurrences and do 1 specific task. If you later also need a function that gets all sheetmetal parts, then you need to write a new function for that. That is also true for what the function does. If you need to do something else then you need to write a new function.

So we if we want to improve this function then we need to extract the following:

  • The selection of the occurrences (requirements).
  • The “Do stuff with the found Occurrence” part of the function.

Making the function do nothing is easy 😉 but in the end we want to do something. There fore I changed the function to returns only the occurrences that meet the requirements. By doing that you could use the same function for multiple actions, as log as the requirements don’t change.

But I also wanted to change the function so that i can change the “selection” part of the function. Without changing the function. For that it would be great if we could use a “function” as a parameter for a function. That is possible with delegates. This is the function that I came up with:

Public Function findAllWhere(doc As AssemblyDocument,
                predicate As Func(Of ComponentOccurrence, Boolean)) As IEnumerable(Of ComponentOccurrence)
    
    Dim list As IEnumerable(Of ComponentOccurrence) = doc.ComponentDefinition.
        Occurrences.Cast(Of ComponentOccurrence).
        Where(predicate)

    Dim assemblyList As IEnumerable(Of ComponentOccurrence) = doc.ComponentDefinition.
        Occurrences.Cast(Of ComponentOccurrence).
        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

 

In the usage example below you will see that is call the function in 2 different ways.
In example 1 I use a lambda expression to select all part occurrences in the assembly.

In example 2 I use the function “partNrContains010” as delegate function for selection all occurrences that have a part number  that contains “010”. It’s important to notice that this function takes 1 argument. An object of the type ComponentOccurrence (and not of the type ComponentOccurrences). And returns a object of the type Boolean.
In both examples I use the returned list to color the part in the list.

Sub Main()
    Dim doc As AssemblyDocument = ThisDoc.Document

    Dim list As IEnumerable(Of ComponentOccurrence)

    ' Usage example 1
    list = findAllWhere(doc, Function(occ) occ.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject)
    colorPartsInList(list, "Gunmetal")
	
    ' Usage example 2
    list = findAllWhere(doc, AddressOf partNrContains010)
    colorPartsInList(list, "Brass - Satin")

    doc.Update()
End Sub

Public Function partNrContains010(occ As ComponentOccurrence) As Boolean
    Dim def As ComponentDefinition = occ.Definition
    Dim doc As Document = def.Document
    Dim propSet As PropertySet = doc.PropertySets.Item("Design Tracking Properties")
    Dim prop As [Property] = propSet.Item("Part Number")
    Dim val As String = prop.Value
    Return (val.Contains("010"))
End Function


Public Sub colorPartsInList(List As IEnumerable(Of ComponentOccurrence), colorName As String)
    For Each occ As ComponentOccurrence In List
        Dim def As ComponentDefinition = occ.Definition
        Dim doc As PartDocument = def.Document
        doc.ActiveRenderStyle = doc.RenderStyles.Item(colorName)
    Next
End Sub

As you see with just 1 function its possible to make all different kind of lists.

 

Skills:

Autodesk Inventor, Vault, Git, C#, vb, .net, php HTML, css, js

Education:

University computer science.
HBO Mechanical engineer.
MBO Fine mechanics.

Experience:

Programmer and Mechanical engineer at Kelvion
(2016 - 20..)

Mechanical engineer at Strukton
(2009 - 2016)

Mechanical engineer at RDG-engineering
(2007 - 2009)

CNC Programmer at VMC
(2005 - 2007)

volunteer at Taizé
(2007)

Certifications:

Objectgeoriënteerd analyseren en ontwerpen, Objectgeoriënteerd programmeren in Java, Webapplicaties: de clientkant, Databases, Security Aware Programmer, Web Security Specialist