Check if item is selected while recursing through BOM

Check if item is selected while recursing through BOM

pball
Mentor Mentor
524 Views
12 Replies
Message 1 of 13

Check if item is selected while recursing through BOM

pball
Mentor
Mentor

I'm making a routine that will recurse through the whole BOM of an assembly and I'd like to be able to check if an item in the BOM is currently selected in the graphics window. I'm aware of ThisApplication.ActiveEditDocument.SelectSet but I'm not sure if that provides enough information to know which instance of an item is selected if there are multiple of the same item and only one is selected.

 

For example if I have the Bom structure shown below and I have Part1.ipt:1 in Asm2.iam selected. I would need a way to track that, so if I wanted to exclude anything selected the routine would exclude the proper instance and/or quantity.

 

Asm1.iam

    Part1.ipt:1

    Part1.ipt:2

        Asm2.iam:1

            Part1.ipt:1

Public Sub test()
    Call BomListRecurse(ThisApplication.ActiveEditDocument)
End Sub

Public Sub BomListRecurse(ByVal oDoc As Document)
    Debug.Print oDoc.FullDocumentName

    If (oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject) And (oDoc.ReferencedDocuments.Count > 0) Then
    Dim RefDoc As Document
        For Each RefDoc In oDoc.ReferencedDocuments
            Call BomListRecurse(RefDoc)
        Next
    ElseIf (oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject) Then
        Dim BomRows As BOMRowsEnumerator
        Set BomRows = oDoc.ComponentDefinition.BOM.BOMViews.Item(1).BomRows
        Dim TempDoc As Document
        Dim oRow As BOMRow
        For Each oRow In BomRows
            If (oRow.ComponentDefinitions.Count > 0) Then
                Set TempDoc = oRow.ComponentDefinitions.Item(1).Document
            Else
                Set TempDoc = ThisApplication.Documents.Open(oRow.ReferencedFileDescriptor.FullFileName, False)
            End If
            Call BomListRecurse(TempDoc)
        Next
    End If
End Sub

 

Check out my style edits for the Autodesk forums
pball's Autodesk Forum Style
0 Likes
Accepted solutions (2)
525 Views
12 Replies
Replies (12)
Message 2 of 13

daltonNYAW9
Advocate
Advocate

try using 'oRow.ComponentOccurrences' instead of 'ComponentDefinitions'

ThisDoc.Document.SelectSet.Clear
For Each oOcc As ComponentOccurrence In oRow.ComponentOccurrences
	ThisApplication.CommandManager.DoSelect(oOcc)
Next
0 Likes
Message 3 of 13

WCrihfield
Mentor
Mentor

You may already know this, but selection can only be done or accessed for the 'active' document.  You already mentioned the Document.SelectSet, which could contain a single ComponentOccurrence object, which could definitely tell you which one is selected.  Another way that is much longer and far less efficient, would be to recurse the model browser tree checking BrowserNode.Selected property value.  Then the BrowserNode.NativeObject could potentially be the ComponentOccurrence object.  However, like Dalton already pointed out, you would likely need to find the BOMRow owning that occurrence by iterating the rows occurrences.  You would not want to be stepping down through referenced documents, or their definitions though, because that looses the lineage with the active document.  Use BOMRow.ChildRows for recursing the BOM to retain lineage with the parent assembly.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 4 of 13

pball
Mentor
Mentor

@daltonNYAW9Could you explain what the ComponentOccurrences would gain me? I'm also confused as that code doesn't seem to relate to what I'm trying to do.

@WCrihfieldWould you be able to expand on how I could use the ComponentOccurrence object? Would I be able to save a ComponentOccurrence object from Document.SelectSet and then while going through the Bom compare that to find matches?

Check out my style edits for the Autodesk forums
pball's Autodesk Forum Style
0 Likes
Message 5 of 13

daltonNYAW9
Advocate
Advocate

You could use the '.ComponentOccurrences' to get the specific occurrences for that bom row.

 

You could create a list at the beginning of your code to save the currently selected parts

Dim oADoc As AssemblyDocument = ThisDoc.Document
Dim oOccs As New List(Of ComponentOccurrence)
For Each oOcc As ComponentOccurrence In oADoc.SelectSet.OfType(Of ComponentOccurrence)
	oOccs.Add(oOcc)
Next

Then later in your sub routine check if the 'ComponentOccurrence' is part of the initial list

For Each oOcc1 As ComponentOccurrence In oRow.ComponentOccurrences
	If oOccs.Contains(oOcc1)
		'matching item found
		MessageBox.Show("Message", "Title")

	End If
Next

 

Message 6 of 13

WCrihfield
Mentor
Mentor

That's mostly what I was suggesting also, but was not sure about your intentions for what to do when a pre-selected item is found, or not found, or how much information may be needed about when or where it is found.  I have a few code routines for recursively iterating BOM's, but don't really use them that much for work related purposes.  So, I took one of those and customized it a bit for this task.  Since I am still not sure what your full intentions are, I just put an iLogic 'Logger' feedback into the process where the pre-selected item gets found.  Not sure if it will help much yet though.

Sub Main
	Dim oInvApp As Inventor.Application = ThisApplication
	Dim oADoc As Inventor.AssemblyDocument = TryCast(oInvApp.ActiveDocument, Inventor.AssemblyDocument)
	If oADoc Is Nothing Then
		'MessageBox.Show("An Assembly Document must be active when you run this rule.", "Wrong Document Type", MessageBoxButtons.OK, MessageBoxIcon.Stop)
		Logger.Debug("Rule named '" & iLogicVb.RuleName & "' did not run because no assembly obtained!")
		Return
	End If
	'this variable is declared between routines, to share access to it
	oPreSelectedOccs = oADoc.SelectSet.OfType(Of Inventor.ComponentOccurrence).ToList()
	If oADoc.RequiresUpdate Then oADoc.Update2(True)
	Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
	Dim oBOM As Inventor.BOM = oADef.BOM
	oBOM.HideSuppressedComponentsInBOM = True
	oBOM.StructuredViewEnabled = True
	oBOM.StructuredViewFirstLevelOnly = False
	Dim oStrBOMView As BOMView = Nothing
	For Each oBOMView As BOMView In oBOM.BOMViews
		If oBOMView.ViewType = BOMViewTypeEnum.kStructuredBOMViewType Then
			oStrBOMView = oBOMView
			Exit For
		End If
	Next 'oBOMView
	If oStrBOMView Is Nothing Then
		Logger.Debug("Structured BOMView Not Found!")
		Return
	End If
	RecurseBOMRows(oStrBOMView.BOMRows)
	If oADoc.RequiresUpdate Then oADoc.Update2(True)
End Sub

Dim oPreSelectedOccs As List(Of Inventor.ComponentOccurrence)

Sub RecurseBOMRows(oBOMRows As Inventor.BOMRowsEnumerator)
	If (oBOMRows Is Nothing) OrElse (oBOMRows.Count = 0) Then Return
	For Each oRow As Inventor.BOMRow In oBOMRows
		'<<< FILTER HERE, IF NEEDED >>>
		'<<< DO TASK HERE >>>
		For Each oRowOcc As ComponentOccurrence In oRow.ComponentOccurrences
			If oPreSelectedOccs.Contains(oRowOcc) Then
				Dim bHasChildRows As Boolean = ((Not oRow.ChildRows Is Nothing) OrElse (oRow.ChildRows.Count = 0))
				Dim iChildRowsCount = 0
				If bHasChildRows Then iChildRowsCount = oRow.ChildRows.Count
				Logger.Info(vbCrLf & _
				"Pre-Selected Occurrence Found In BOM" & vbCrLf & _
				"Occurrence Name:  " & oRowOcc.Name & vbCrLf & _
				"BOMRow Item Number:  " & oRow.ItemNumber & vbCrLf & _
				"BOMRow Total Quantity:  " & oRow.TotalQuantity & vbCrLf & _
				"BOMRow Has Child Rows:  " & bHasChildRows & vbCrLf & _
				"BOMRow Child Rows Count:  " & iChildRowsCount.ToString)
			Else
				'what to do when this row does not contain a pre-selected item
			End If
		Next 'oRowOcc
		'<<< RECURSE DOWN INTO LOWER LEVELS, IF ANY >>>
		If Not oRow.ChildRows Is Nothing Then RecurseBOMRows(oRow.ChildRows)
	Next 'oRow
End Sub

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

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 13

pball
Mentor
Mentor

Thank you both for the further explanations. This got me closer to my goal. Though selecting an item in a sub assembly does not get picked up. I'm guessing that the ComponentOccurrence in the SelectSet doesn't match the occurrence when traversing the BOM. I've attached a test assembly with my code and @WCrihfield code saved as iLogic inside of it. Both sets of code behave the same when an item in a sub assembly is selected. Any ideas on how to capture if Bom Test p1 is selected inside of Bom Test s1 while running the code from the Bom Test assembly?

 

As for what I'm trying to do if anyone is interested. I have a bunch of different "scripts" in my addin with a couple different routines for generating a list of items in an assembly to be processed. I'm finally getting around to make a more generic function that will create a full BOM list with every property for each item I can imagine using. Then I'll parse this list to get items to print, export as a csv for our ERP system, export a list of bolts to order, or anything else. I found out with my previous iterations that creating a full BOM list and then removing anything in the SelectSet from it can result in incorrect quantities. So my thought is to remove items while traversing the BOM if that item is selected.

Check out my style edits for the Autodesk forums
pball's Autodesk Forum Style
0 Likes
Message 8 of 13

WCrihfield
Mentor
Mentor
Accepted solution

I know you attempted to explain why you needed this, but since I don't work with add-ins, don't work directly with an ERP system, and don't need any special lists 'to be processed' that I can only get from a BOM, I gave up on understanding why.  😂  Not only that, but after digging around in that very awkward situation for a while, I still don't know if I have a good solution yet, but I need to shift my attention elsewhere now, and will post the code I have at this point, in case you want to review it for any other ideas.  To be honest, its starting to make my head hurt, because not only is it a bit complicated, but I have no use for it either.

I'm pretty sure the catch here is that the pre-selected occurrences is actually a 'proxy' (ComponentOccurrenceProxy), not just a regular one.  While the pre-selected one is a proxy, it always has multiple items in its 'occurrence path', while the row occurrence always seems to just have one item in its path, for some reason.  Once you get the 'NativeObject' of that proxy, you eliminate some of the confusion, but also start finding multiple matches.  The one you want is obviously at the lower level, with the sub assembly in its occurrence path.  I usually avoid navigating the BOM if at all possible, and if there is any other way to achieve what I am after.  But I digress.  😓

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 13

daltonNYAW9
Advocate
Advocate

Two other ways I thought about doing this...
1. checking if the '.RangeBox' or '.PreciceRangeBox' cordinates match

2. Comparing the '.OccurrencePath' value

 

Dont have a working example, but just a thought.

0 Likes
Message 10 of 13

pball
Mentor
Mentor

The code @WCrihfield posted attached to his previous post works quite well. I was able to clean things up and add more code to work with patterns and pattern elements inside of the SelectSet. For now this should be able to capture any selected items inside of an assembly.

 

Below is my latest code and a new test assembly is attached with this code in it already.

 

Class stuff
Dim oOccs As New List(Of ComponentOccurrence)

Sub main
	Dim startMarker = "------ Custom iLogic Log marker --------"
	iLogicVb.Automation.LogControl.Level = LogLevel.Debug
	Logger.Debug(startMarker)
	
	Dim oDoc As Document = ThisApplication.ActiveEditDocument
	
	'Loop through all component occurrences in the selectset
	For Each oOcc As ComponentOccurrence In oDoc.SelectSet.OfType(Of ComponentOccurrence)
		If (TypeOf oOcc Is ComponentOccurrenceProxy) Then
			oOccs.Add(oOcc.NativeObject)
		Else
			oOccs.Add(oOcc)
		End If
		Logger.Debug(vbclf & "component occurrence" & oOcc.Definition.Document.fullfilename)
	Next
	'Loop through all patterns in the selectset
	For Each Item As OccurrencePattern In oDoc.SelectSet.OfType(Of OccurrencePattern)
		For Each subItem As OccurrencePatternElement In Item.OccurrencePatternElements
			For Each oOcc As ComponentOccurrence In subItem.Occurrences
				Logger.Debug(vbclf & "pattern element: " & oOcc.Name)
				oOccs.add(oOcc)
			Next
		Next
	Next
	'Loop through all pattern elements in selectset
	For Each Item As OccurrencePatternElement In oDoc.SelectSet.OfType(Of OccurrencePatternElement)
		For Each oOcc As ComponentOccurrence In Item.Occurrences
			Logger.Debug(vbclf & "element: " & oOcc.Name)
			oOccs.add(oOcc)
		Next
	Next

	Logger.Debug("")
	Dim BomRows As BOMRowsEnumerator = oDoc.ComponentDefinition.BOM.BOMViews.Item(1).BOMRows
	Call BomListRecurse(BomRows)
	
	iLogicVb.Automation.LogControl.Level = LogLevel.Warn
	
	Dim logFileName = "C:\temp\iLogic Log Example.txt"
	iLogicVb.Automation.LogControl.SaveLogAs(logFileName)

	Dim logText = System.IO.File.ReadAllText(logFileName)
	Dim markerIndex = logText.LastIndexOf(startMarker)
	System.IO.File.WriteAllText(logFileName, logText.Substring(markerIndex))
End Sub

Public Sub BomListRecurse(ByVal BomRows As BOMRowsEnumerator)
	If (BomRows Is Nothing) OrElse (BomRows.Count = 0) Then Return
		Dim Count As Integer
        For Each oRow As BOMRow In BomRows
			Count = 0
			For Each oOccsRow As ComponentOccurrence In oRow.ComponentOccurrences
				If (oOccs.Contains(oOccsRow)) Then
					Count += 1
				End If
			Next
			Logger.Debug(vbCrLf & "{0} is selected {1} times",oRow.ComponentOccurrences.Item(1).Definition.Document.fullfilename,Count)

            If (oRow.ChildRows IsNot Nothing) AndAlso (oRow.ChildRows.Count > 0) Then Call BomListRecurse(oRow.ChildRows)
        Next
End Sub
End Class

 

Check out my style edits for the Autodesk forums
pball's Autodesk Forum Style
0 Likes
Message 11 of 13

pball
Mentor
Mentor

Well further testing revealed an issue and I'm at wits end trying resolve it. The previous code works great if the selected item is in the main assembly or a sub assembly. But if you select a part inside a sub sub assembly the code gets confused and lists more than the selected as being selected.

 

An updated test assembly has been attached. If Bom Test p1 is selected from either instance of Bom Test S1 the code is unable to tell the difference and marks both Bom Test p1 parts as selected that are inside of Bom Test S1.

Bom Test

    Bom Test S1

        Bom Test p1

    Bom Test S2

        Bom Test S1

            Bom Test p1

 

The iLogic script pball is the original code and pball v2 is the code below.

 

I tried updating my code to track the parent occurrences but that doesn't work as soon as the selected item is one sub assembly deep. Having it output the name of each occurrence it looks like it should be working, but something is apparently off and it's hard to debug since I'm not aware of a unique id or the like that can be gotten from a componentoccurrence.

 

@johnsonshiueor @CGBenner I don't know how much API stuff you know but do you know anyone that might be help me out with this? Thanks

 

 

Class stuff

Sub main
	Dim startMarker = "------ Custom iLogic Log marker --------"
	iLogicVb.Automation.LogControl.Level = LogLevel.Debug
	Logger.Debug(startMarker)
	
	Dim oDoc As Document = ThisApplication.ActiveEditDocument
	
	Logger.Debug("")
	Dim oDocBomRows As BOMRowsEnumerator = oDoc.ComponentDefinition.BOM.BOMViews.Item(1).BOMRows
	Call BomListRecurse(oDocBomRows,GetSelectedOccurrences(oDoc))
	
	iLogicVb.Automation.LogControl.Level = LogLevel.Warn
	
	Dim logFileName = "C:\temp\iLogic Log Example.txt"
	iLogicVb.Automation.LogControl.SaveLogAs(logFileName)

	Dim logText = System.IO.File.ReadAllText(logFileName)
	Dim markerIndex = logText.LastIndexOf(startMarker)
	System.IO.File.WriteAllText(logFileName, logText.Substring(markerIndex))
End Sub

Public Function GetSelectedOccurrences(oDoc As Document) As List(Of List(Of ComponentOccurrence))
	Dim Selected As New List(Of List(Of ComponentOccurrence))
	Dim SelTemp As New List(Of ComponentOccurrence)

	'Loop through all component occurrences in the selectset
	For Each oOcc As ComponentOccurrence In oDoc.SelectSet.OfType(Of ComponentOccurrence)
		GetSelectedOccurrencesRecurse(oOcc, SelTemp)
		Selected.Add(SelTemp.ToList)
		SelTemp.Clear()
		Logger.Debug(vbclf & "component occurrence" & oOcc.Definition.Document.fullfilename)
	Next
	'Loop through all patterns in the selectset
	For Each Item As OccurrencePattern In oDoc.SelectSet.OfType(Of OccurrencePattern)
		For Each subItem As OccurrencePatternElement In Item.OccurrencePatternElements
			For Each oOcc As ComponentOccurrence In subItem.Occurrences
				GetSelectedOccurrencesRecurse(oOcc, SelTemp)
				Selected.Add(SelTemp.ToList)
				SelTemp.Clear()
				Logger.Debug(vbclf & "pattern element: " & oOcc.Name)
			Next
		Next
	Next
	'Loop through all pattern elements in selectset
	For Each Item As OccurrencePatternElement In oDoc.SelectSet.OfType(Of OccurrencePatternElement)
		For Each oOcc As ComponentOccurrence In Item.Occurrences
			GetSelectedOccurrencesRecurse(oOcc, SelTemp)
			Selected.Add(SelTemp.ToList)
			SelTemp.Clear()
			Logger.Debug(vbclf & "element: " & oOcc.Name)
		Next
	Next

	Return Selected
End Function

Private Sub GetSelectedOccurrencesRecurse(oOcc As ComponentOccurrence, SelTemp As List(Of ComponentOccurrence))
	SelTemp.Insert(0, oOcc)
	If (oOcc.ParentOccurrence IsNot Nothing) Then GetSelectedOccurrencesRecurse(oOcc.ParentOccurrence, SelTemp)
End Sub
   
Public Sub BomListRecurse(ByVal BomRows As BOMRowsEnumerator, Selected As List(Of List(Of ComponentOccurrence)), Optional oOccList As List(Of ComponentOccurrence) = Nothing)
	Dim oDoc As Document

	If (oOccList Is Nothing) Then oOccList = New List(Of ComponentOccurrence)
	For Each oRow As BOMRow In BomRows
		Dim FoundSelected As Boolean = False
		If (Selected.Count > 0) Then
			For Each oOccsRow As ComponentOccurrence In oRow.ComponentOccurrences
				Dim txt As New List(Of String)
				Dim txt2 As New List(Of String)
				For Each item As ComponentOccurrence In oOccList.Append(oOccsRow).ToList
					txt.Add(item.Name)
				Next
				For Each item As ComponentOccurrence In Selected(0).ToList
					txt2.Add(item.Name)
				Next
				Logger.Debug(vbCrLf & "Selected:" & String.Join(" ", txt2.ToArray) & vbCrLf & "Current oOcc: " &String.Join(" ", txt.ToArray))

				If (Selected.Any(Function(x) x.SequenceEqual(oOccList.Append(oOccsRow).ToList))) Then
					Logger.Debug(vbCrLf & "Found selected item")
				End If
			Next
		End If
		
		If (oRow.ChildRows IsNot Nothing) AndAlso (oRow.ChildRows.Count > 0) Then BomListRecurse(oRow.ChildRows, Selected, oOccList.Append(oRow.ComponentOccurrences.Item(1)).ToList)
	Next
End Sub
End Class

 

 

Check out my style edits for the Autodesk forums
pball's Autodesk Forum Style
0 Likes
Message 12 of 13

WCrihfield
Mentor
Mentor

I don't really have much time right now to jump back into this, but I still think the main detail causing problems here is the 'context' related to 'proxy levels'.

  • When there are more than 2 levels (steps in assembly structure) in a 'main' (highest level) assembly...
    • The 'NativeObject' of a proxy can actually be another proxy.
    • A proxy is not always in the 'context' of the 'main' (highest level) assembly.
  • If you access the 'definition' (ComponentDefinition) of a proxy, then you are accessing the 'context' where the true 'original' was created.
    • But once in the definition of a proxy, you then have to find the source object again, in that context.

I believe we can actually 'recurse' the levels (or contexts) of proxies, in either direction.

 

As an example, lets look at the 'Face' of a part ("Part 1.ipt").  An occurrence of that part is placed into an assembly, making the default name of that occurrence "Part 1:1", then that assembly is saved as "Asm 1.iam".  Then an occurrence of that assembly is placed into a second assembly, where that occurrence of the assembly gets named "Asm1:1", then that second assembly gets saved as "Asm 2.iam".  At this point, 'Asm 1' is a sub assembly within 'Asm 2'.  Then we have the following structure.

  •  Asm 2  (contains occurrence named "Asm 1:1")
    • Asm 1 (contains occurrence named "Part 1:1")
      • Part 1 (contains original Face object 'Face 1")
        • Face 1 (just a Face, within that part)

(It gets even more confusing when there are 'parallel' occurrences/instances of the same part at multiple levels of the assembly, but I won't go there right now, to keep the 'concept' simple.)

In the scenario where I want to get and use that face of that part in the context of the main assembly (which will be a FaceProxy object), I usually have to start from the bottom (lowest level), then work my way back up.  In that process, I start with the true original Face object that is in the context/definition of the part, and the lowest level component occurrence (ComponentOccurrence object) of that part, which is in the context of the assembly named 'Asm 1'.  At that point, I use that component occurrence's  ComponentOccurrence.CreateGeometryProxy method, to get the first proxy of that part's face, which will be in same context as the component occurrence (in the context of 'Asm 1').  But we are not done yet, because that proxy is not in the context of 'Asm 2', where we need it.  So next, I need to do that last step another time, but this time we will be using the method from the component occurrence object representing the sub assembly named 'Asm 1', and the proxy we got from the first step.  In this step we will be getting a proxy of a proxy, instead of a proxy of an original.  The proxy we get from that second step will finally be in the 'context' of 'Asm 2'.  We can then use that final resulting proxy for measurements &/or constraints directly in the context of the assembly named 'Asm 2'.

 

Similarly, going the other direction, if we are starting from the context of 'Asm 2', and want to access the 'true original' 'Face 1' in that part (not just a proxy of it), we select the 'proxy' of it in the context of 'Asm 2' first.  Then we use that proxy's 'NativeObject' property to get a reference to the 'proxy' that is in the context of 'Asm 1'.  Then we use the 'NativeObject' property of that resulting proxy to get to the 'true original' in the part.

There are two levels of proxies in that process, in either direction, not just one.  That concept of there possibly being multiple 'levels' of proxies, with each being in a different 'context', trips up most folks, and can be difficult to picture in our heads.  Especially when the proxy is a ComponentOccurrenceProxy, instead of just the proxy of a face or edge.

I always seem to end up trying to explain too much when I start typing about something interesting.  😄

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 13 of 13

pball
Mentor
Mentor
Accepted solution

Well I managed to work something out that appears to work as intended. Below is the test code I ended up with. The RemoveSelected variable when set to true will remove selected items and set to false will only include selected items.

 

Class main
	Sub main
		Dim startMarker = "------ Custom iLogic Log marker --------"
		iLogicVb.Automation.LogControl.Level = LogLevel.Debug
		Logger.Debug(startMarker)
	
		Dim oDoc As Document = ThisApplication.ActiveEditDocument
		Dim RemoveSelected As Boolean = False
		Dim Quantity As Integer = 1
		Dim WhereUsed = ""
		Logger.Debug("")
		If (RemoveSelected) Then
			Logger.Debug(System.IO.Path.GetFileName(oDoc.FullDocumentName) & " qty: 1" )
    		'BomListAdd(oDoc, FullBomTree, Quantity, WhereUsed, False)
		Else
   			Quantity = 0
		End If

		Dim oDocBomRows As BOMRowsEnumerator = oDoc.ComponentDefinition.BOM.BOMViews.Item(1).BOMRows
		BomListRecurse(oDocBomRows, Quantity, WhereUsed, RemoveSelected, GetSelectedOccurrences(oDoc))
	
		iLogicVb.Automation.LogControl.Level = LogLevel.Warn
	
		Dim logFileName = "C:\temp\iLogic Log Example.txt"
		iLogicVb.Automation.LogControl.SaveLogAs(logFileName)

		Dim logText = System.IO.File.ReadAllText(logFileName)
		Dim markerIndex = logText.LastIndexOf(startMarker)
		System.IO.File.WriteAllText(logFileName, logText.Substring(markerIndex).Replace("DEBUG|",""))
	End Sub


    Private Sub BomListRecurse(ByVal BomRows As BOMRowsEnumerator, ByVal Quantity As Integer, WhereUsed As String, RemoveSelected As Boolean, Selected As List(Of List(Of String)), Optional InSeperableChild As Boolean = False, Optional oOccList As List(Of String) = Nothing, Optional AllSub As Boolean = False)
        Dim oDoc As Document
        Dim InSepChildTemp As Boolean
        Dim ListTemp As New List(Of String)
        Dim Count As Integer
        Dim Qty As Integer
        If (oOccList Is Nothing) Then oOccList = New List(Of String)
        For Each oRow As BOMRow In BomRows
            Count = 0
            Dim FoundSelected As Boolean = False
            ListTemp = oOccList.Append(Strings.Split(oRow.ComponentOccurrences.Item(1).Name, ":")(0)).ToList
            If (Selected.Count > 0) Then
                Count = Selected.Where(Function(x) x.SequenceEqual(ListTemp)).Count
                If (Count > 0) Then 
					FoundSelected = True
					Logger.Debug("count: " & Count)
				End If
            End If

            If (RemoveSelected) Or (FoundSelected = False) Then
                Qty = (Quantity * oRow.ItemQuantity) - Count
			ElseIf (AllSub) Then
				Qty = Quantity + Count
            Else
				Logger.Debug("uhhhhhh")
                Qty = Count
            End If

            If (Qty > 0) Then
                oDoc = oRow.ComponentOccurrences.Item(1).Definition.Document
				Logger.Debug(WhereUsed & IIf(WhereUsed <> ""," | ","") & System.IO.Path.GetFileName(oDoc.fulldocumentname) & " qty: " & Qty)
                'BomListAdd(oDoc, FullBomTree, Qty, WhereUsed, InSeperableChild)
                'If (IsPartDoc(oDoc) Or IsWeldmentDoc(oDoc) Or IsPurchasedBomStructure(oDoc)) Then InSepChildTemp = True
				If (RemoveSelected = False) Then AllSub = True
            End If
			If (oRow.ChildRows IsNot Nothing) AndAlso (oRow.ChildRows.Count > 0) Then BomListRecurse(oRow.ChildRows, Qty, oRow.ComponentOccurrences.Item(1).Name, RemoveSelected, Selected, InSepChildTemp, ListTemp, AllSub)
			'InSepChildTemp = InSeperableChild
		Next
    End Sub

    Public Function GetSelectedOccurrences(oDoc As Document) As List(Of List(Of String))
        Dim Selected As New List(Of List(Of String))
        Dim SelTemp As New List(Of String)

        'Loop through all component occurrences in the selectset
        For Each oOcc As ComponentOccurrence In oDoc.SelectSet.OfType(Of ComponentOccurrence)
            For Each Path As ComponentOccurrence In oOcc.OccurrencePath
                SelTemp.Add(Strings.Split(Path.Name, ":")(0))
            Next
            Selected.Add(SelTemp.ToList)
            SelTemp.Clear()
        Next
        'Loop through all patterns in the selectset
        For Each Item As OccurrencePattern In oDoc.SelectSet.OfType(Of OccurrencePattern)
            For Each subItem As OccurrencePatternElement In Item.OccurrencePatternElements
                For Each oOcc As ComponentOccurrence In subItem.Occurrences
                    For Each Path As ComponentOccurrence In oOcc.OccurrencePath
                        SelTemp.Add(Strings.Split(Path.Name, ":")(0))
                    Next
                    Selected.Add(SelTemp.ToList)
                    SelTemp.Clear()
                Next
            Next
        Next
        'Loop through all pattern elements in selectset
        For Each Item As OccurrencePatternElement In oDoc.SelectSet.OfType(Of OccurrencePatternElement)
            For Each oOcc As ComponentOccurrence In Item.Occurrences
                For Each Path As ComponentOccurrence In oOcc.OccurrencePath
                    SelTemp.Add(Strings.Split(Path.Name, ":")(0))
                Next
                Selected.Add(SelTemp.ToList)
                SelTemp.Clear()
            Next
        Next

        Return Selected
    End Function

End Class

 

Check out my style edits for the Autodesk forums
pball's Autodesk Forum Style
0 Likes