Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Recursive BOM. Need some help

4 REPLIES 4
SOLVED
Reply
Message 1 of 5
machiel.veldkamp
569 Views, 4 Replies

Recursive BOM. Need some help

Hi!

 

I use a copied piece of recursive code in my iLogic Rule and I have some issues. 

I already 'fixed' it for IPT's but I still get incorrect numbers for assemblies (in large assemblies)

 

First example of code is located in Main()

Now, I already found out earlier that the part quantities didn't behave as intended so I 'fixed' it by just reading the parts only quantities. 

 

However. It's not right and I need to fix it for real this time. 

 

 

BUT! I don't quite know how it works. Can anyone help me out in understanding recursive code like the one below?

I'm curious about the RecurseBOMRow() and SetRowProps()

 

Correct me if I'm wrong:

RecurseBOMRow travels through the first parts of the assembly (if it has no additional rows)

If it has more rows inside the bom it will call itself

 

SetRowProps Sets the QTY integer which then is passed to the oTotalDict (VBA Dictionary)

 

 

How does SetRowProps set the amounts though? 

 

 

 

 

	Dim oBOMRow As BOMRow
	Dim oCompDef As ComponentDefinition

	For Each oBOMRow In oBOMView.BOMRows
		oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, xProduce)
		If Not oBOMRow.ChildRows Is Nothing
			Call RecurseBOMRow(oBOMRow, oTotalDict, xProduce)
		End If
	Next

	Trace.WriteLine("Making Partsonly QTY's (NOT INTENDED)")
	Try
		oBOMView = oBOM.BOMViews.Item("Parts Only")
	Catch
		MessageBox.Show("BOM not accessible. PARTS ONLY DISABLED?", "IAM Bulk Drawing Tool")
		vaultaddin.Activate
		Exit Sub
	End Try

	For Each oBOMRow In oBOMView.BOMRows
		oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
		Dim CompFileNameOnly As String
		Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
		CompFileNameOnly = CompFullDocumentName.Substring(index + 1)
		QTY = oBOMRow.TotalQuantity * xProduce
		oTotalDict(CompFullDocumentName) = QTY
	Next

 

Sub RecurseBOMRow(oBOMRow As BOMRow, oTotalDict As Dictionary(Of String, Integer), xProduce As Integer)
	For Each oBOMRow In oBOMRow.ChildRows
		Dim oCompDef As ComponentDefinition
		oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, xProduce)
		If Not oBOMRow.ChildRows Is Nothing
			Call RecurseBOMRow(oBOMRow, oTotalDict, xProduce)
		End If
	Next
End Sub

Sub SetRowProps(oCompDef As ComponentDefinition, QTY As Integer, oTotalDict As Dictionary(Of String, Integer), xProduce As Integer)
	Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
	Dim CompFileNameOnly As String
	Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
	CompFileNameOnly = CompFullDocumentName.Substring(index + 1)
	QTY = QTY * xProduce
	oTotalDict(CompFullDocumentName) = QTY
End Sub

 

Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below.

___________________________
4 REPLIES 4
Message 2 of 5

I did some testing to see what happens. 

 

I think I am not using oBOMRow.TotalQuantity correct. 

 

See I though that oBOMRow.TotalQuantity would give me the total quantity in the who;e assembly but I think it only returns the quantitiy in the assembly it's directly in. 

 

Example pic below:

partnumber: 1-60-00022

Expected QTY: 2*1*6=12

oBOMRow.TotalQuantity returns: 2

 

SO i'll have to make something that notifies the SetRowProps of the QTY of the assembly it is looking in. 

I think. 

 

image.png

Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below.

___________________________
Message 3 of 5

Im using this to test my assembly:

 

I could really use some help. I'm trying to make a VBA Dictionary containing the path (C:\location\filename.extention) As string & Total Quantity As Integer of all parts AND assemblies in the top assembly

 

Sub main()

	If ThisApplication.ActiveDocument.DocumentType <> kAssemblyDocumentObject Then
		MessageBox.Show("Please run this rule from the ASSEMBLY file.", "iLogic")
		Exit Sub
	End If

	Trace.WriteLine("**************START****************")

	'- - - - - - - - - - - - - -  MAKE BOM - - - - - - - - - - - - - '
	Trace.WriteLine("MAKE BOM")
	Dim oAsmDoc As AssemblyDocument
	oAsmDoc = ThisApplication.ActiveDocument
	Dim oTotalDict As New Dictionary(Of String, Integer)


	'Wanna keep: LOD Settings
	Dim oLOD As LevelOfDetailRepresentation
	Dim UserLOD As LevelOfDetailRepresentation
	UserLOD = oAsmDoc.ComponentDefinition.RepresentationsManager.ActiveLevelOfDetailRepresentation
	oAsmDoc.ComponentDefinition.RepresentationsManager.LevelOfDetailRepresentations("Master").Activate
	Trace.WriteLine("LOD is now master")
	Dim oAssyDef As AssemblyComponentDefinition = oAsmDoc.ComponentDefinition
	Dim oBOM As BOM = oAssyDef.BOM
	oBOM.StructuredViewEnabled = True
	oBOM.StructuredViewFirstLevelOnly = False

	Dim oBOMView As BOMView = oBOM.BOMViews.Item("Structured")
	oBOMView.Sort2("Part Number", True)

	Dim oBOMRow As BOMRow
	Dim oCompDef As ComponentDefinition

	Trace.WriteLine("**************MAKE BOM NOW****************")
	Dim i As Integer = 1
	For Each oBOMRow In oBOMView.BOMRows
		Trace.WriteLine("NUMBER - " & i)
	
		oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		Trace.WriteLine("***")
		Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, 1)
		If Not oBOMRow.ChildRows Is Nothing
			Call RecurseBOMRow(oBOMRow, oTotalDict, 1)
		End If
		i = i + 1 
	Next
	Trace.WriteLine("****************BOM***********")
	For i = 0 To oTotalDict.Count - 1
		Key = oTotalDict.Keys(i)
		oCount = oTotalDict.Values(i)
		
		Trace.WriteLine(Key & " : " & oCount)
	Next
	'- - - - - - - - - -  Windows Voice - - - - - - - - - - 
	'	Dim objSPVoice, colVoices
	'	objSPVoice = CreateObject("SAPI.SpVoice")
	'	objSPVoice.Speak("attention: rule finished")
	Trace.WriteLine("***************** END ********************")

End Sub


Sub RecurseBOMRow(oBOMRow As BOMRow, oTotalDict As Dictionary(Of String, Integer), xProduce As Integer)
	Trace.WriteLine("START of RecurseBOMRow")
	Trace.WriteLine("Print:" & oBOMRow.ComponentDefinitions.Item(1).Document.FullDocumentName)
	
	For Each oBOMRow In oBOMRow.ChildRows
		Trace.WriteLine("LEVEL: " & j)
		Dim oCompDef As ComponentDefinition
		oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		
		Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, xProduce)

		If Not oBOMRow.ChildRows Is Nothing
			Trace.WriteLine("CHILDROWS = 0... ")
			Call RecurseBOMRow(oBOMRow, oTotalDict, xProduce)
		End If
		j = j + 1
	Next
	
End Sub

Sub SetRowProps(oCompDef As ComponentDefinition, QTY As Integer, oTotalDict As Dictionary(Of String, Integer), xProduce As Integer)
	Trace.WriteLine("SetRowProps")
	Trace.WriteLine("Print:" & oCompDef.Document.FullDocumentName)
	Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
	Dim CompFileNameOnly As String
	Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
	CompFileNameOnly = CompFullDocumentName.Substring(index + 1)
		
	If oTotalDict.ContainsKey(CompFullDocumentName) = True Then
		Trace.WriteLine("|    EXISTS. ADD TO +KEY")
		' oKey = oTotalDict.Keys(CompFullDocumentName)
		' oCount = oTotalDict.Values(CompFullDocumentName)
		' Trace.WriteLine(oKey & " - " & oCount)
		KeyValue = oTotalDict(CompFullDocumentName)
		
		oTotalDict(CompFullDocumentName) = KeyValue + QTY
	Else
		Trace.WriteLine("|    NEW MAKE NEW *KEY")
		oTotalDict(CompFullDocumentName) = QTY
	End If
	
	Trace.WriteLine("SET TO:" & CompFullDocumentName  & " : " & oTotalDict(CompFullDocumentName))
End Sub





 

Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below.

___________________________
Message 4 of 5

Making some progress. WIll clean up later.

 

For those who are following. Download DebugView to see whats happening behind the scenes.

 

Sub main()

If ThisApplication.ActiveDocument.DocumentType <> kAssemblyDocumentObject Then
	MessageBox.Show("Please run this rule from the ASSEMBLY file.", "iLogic")
	Exit Sub
End If

Trace.WriteLine("**************START****************")

'- - - - - - - - - - - - - -  MAKE BOM - - - - - - - - - - - - - '
Trace.WriteLine("MAKE BOM")
Dim oAsmDoc As AssemblyDocument
oAsmDoc = ThisApplication.ActiveDocument
Dim oTotalDict As New Dictionary(Of String, Integer)


'Wanna keep: LOD Settings
Dim oLOD As LevelOfDetailRepresentation
Dim UserLOD As LevelOfDetailRepresentation
UserLOD = oAsmDoc.ComponentDefinition.RepresentationsManager.ActiveLevelOfDetailRepresentation
oAsmDoc.ComponentDefinition.RepresentationsManager.LevelOfDetailRepresentations("Master").Activate
Trace.WriteLine("LOD is now master")
Dim oAssyDef As AssemblyComponentDefinition = oAsmDoc.ComponentDefinition
Dim oBOM As BOM = oAssyDef.BOM
oBOM.StructuredViewEnabled = True
oBOM.StructuredViewFirstLevelOnly = False

Dim oBOMView As BOMView = oBOM.BOMViews.Item("Structured")
oBOMView.Sort("Item", True)

Dim oBOMRow As BOMRow
Dim oCompDef As ComponentDefinition

Trace.WriteLine("**************MAKE BOM NOW****************")
Dim xProduce As Integer = 1 ' production amount. Should act as a multipier

Dim i As Integer = 1
For Each oBOMRow In oBOMView.BOMRows
	Trace.WriteLine("***START NUMBER " & i)
	oCompDef = oBOMRow.ComponentDefinitions.Item(1)
	Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, xProduce)
	If Not oBOMRow.ChildRows Is Nothing
		Call RecurseBOMRow(oBOMRow, oTotalDict, oBOMRow.TotalQuantity)
	End If
	Trace.WriteLine("***END NUMBER " & i)
	i = i + 1
Next
Trace.WriteLine("****************BOM***********")

Dim oCount As Integer = 0
For i = 0 To oTotalDict.Count - 1
	Key = oTotalDict.Keys(i)
	oCount = oTotalDict.Values(i)
	' Trace.WriteLine(Key & " : " & oCount)
	Number = oTotalDict.Values(i)
	oCount = Number * xProduce
	oTotalDict(Key) = oCount
	oCount = oTotalDict.Values(i)
	Trace.WriteLine(Key & " : " & oCount)
Next
'- - - - - - - - - -  Windows Voice - - - - - - - - - - 
'	Dim objSPVoice, colVoices
'	objSPVoice = CreateObject("SAPI.SpVoice")
'	objSPVoice.Speak("attention: rule finished")
Trace.WriteLine("***************** END ********************")
i = i / 0
End Sub


Sub RecurseBOMRow(oBOMRow As BOMRow, oTotalDict As Dictionary(Of String, Integer), newParentQTY As Integer)
	Trace.WriteLine("START of RecurseBOMRor for: " & oBOMRow.ComponentDefinitions.Item(1).Document.FullDocumentName & "QTY = " & oBOMRow.TotalQuantity & " Parent = " & newParentQTY )
	ParentQTY = oBOMRow.TotalQuantity
	For Each oBOMRow In oBOMRow.ChildRows
		' Trace.WriteLine("LEVEL: " & j)
		Dim oCompDef As ComponentDefinition
		oCompDef = oBOMRow.ComponentDefinitions.Item(1)

		Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, newParentQTY)

		If Not oBOMRow.ChildRows Is Nothing
			Trace.WriteLine("------------------------------------------------------------------: " & oBOMRow.ComponentDefinitions.Item(1).Document.FullDocumentName)
			Call RecurseBOMRow(oBOMRow, oTotalDict, ParentQTY)
		End If
		' j = j + 1
	Next

End Sub

Sub SetRowProps(oCompDef As ComponentDefinition, QTY As Integer, oTotalDict As Dictionary(Of String, Integer), newParentQTY As Integer)
	Trace.WriteLine("START SetRowProps for " & oCompDef.Document.FullDocumentName & " QTY is: " & QTY & " Parent = " & newParentQTY )

	Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
	Dim CompFileNameOnly As String
	Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
	CompFileNameOnly = CompFullDocumentName.Substring(index + 1)
	If oTotalDict.ContainsKey(CompFullDocumentName) = True Then
		' oKey = oTotalDict.Keys(CompFullDocumentName)
		' oCount = oTotalDict.Values(CompFullDocumentName)
		' Trace.WriteLine(oKey & " - " & oCount)
		KeyValue = oTotalDict(CompFullDocumentName)
		QTY = QTY + KeyValue
		oTotalDict(CompFullDocumentName) = QTY * newParentQTY
		
		Trace.WriteLine("EXISTING KEY. QTY = " & oTotalDict(CompFullDocumentName))
	Else
		
		oTotalDict(CompFullDocumentName) = QTY * newParentQTY
		Trace.WriteLine("NEW KEY. QTY = " & oTotalDict(CompFullDocumentName))
	End If



	' Trace.WriteLine("SET TO: " & oTotalDict(CompFullDocumentName))
	' Trace.WriteLine("END SetRowProps")
End Sub




 

 

 

Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below.

___________________________
Message 5 of 5

Fixed it!

Commented the code for clarity.

 

If you have Debugview installed you can uncomment some of the Trace.WriteLine to see whats happening where.

 

The code has a Recursor for the entire BOM. It gives the recursed object a parent amount and multiplies that to the object quantity to get the total quantity.

 

In the case some abritrary subassembly is encountered more than once, the current value is added to the totalvalue. You can see that in SetRowProps()

I also included a Total Multiplier in the case of a thing where you want to multiply everything by X amount. (it's an integer. )

 

 

 

 

Sub main()

If ThisApplication.ActiveDocument.DocumentType <> kAssemblyDocumentObject Then
	MessageBox.Show("Please run this rule from the ASSEMBLY file.", "iLogic")
	Exit Sub
End If

Trace.WriteLine("**************START RULE****************")

Dim oTotalDict As New Dictionary(Of String, Integer) 	' VBA Dictionary which will hold the path and total QTY of all assemblies and parts. 
Dim xProduce As Integer = 1 							' production amount. Acts as a multipier

'Wanna keep: LOD Settings
Dim oLOD As LevelOfDetailRepresentation
Dim oAsmDoc As AssemblyDocument = ThisApplication.ActiveDocument
	oAsmDoc.ComponentDefinition.RepresentationsManager.LevelOfDetailRepresentations("Master").Activate
Dim oAssyDef As AssemblyComponentDefinition = oAsmDoc.ComponentDefinition
Dim oBOM As BOM = oAssyDef.BOM
	oBOM.StructuredViewEnabled = True
	oBOM.StructuredViewFirstLevelOnly = False
Dim oBOMView As BOMView = oBOM.BOMViews.Item("Structured")
Dim oBOMRow As BOMRow
Dim oCompDef As ComponentDefinition

Trace.WriteLine("**************MAKE BOM ****************")

For Each oBOMRow In oBOMView.BOMRows
	oCompDef = oBOMRow.ComponentDefinitions.Item(1)
	Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, 1) 		' Set the oTotalDict Key and Value for this object
	If Not oBOMRow.ChildRows Is Nothing
		Call RecurseBOMRow(oBOMRow, oTotalDict, oBOMRow.TotalQuantity)
	End If
Next
Trace.WriteLine("****************SHOW BOM***********")

Dim oCount As Integer = 0
Dim i As Integer
For i = 0 To oTotalDict.Count - 1
	Key = oTotalDict.Keys(i)
	oCount = oTotalDict.Values(i)
	' Trace.WriteLine(Key & " : " & oCount) 		' Before xProduce
	Number = oTotalDict.Values(i)
	oCount = Number * xProduce
	oTotalDict(Key) = oCount
	oCount = oTotalDict.Values(i)
	Trace.WriteLine(Key & " : " & oCount) 		' After xProduce
Next

MessageBox.Show("oTotalDict Now holds all parts And assemblies In a random ish Order. xProduce Is a total multiplier. ", "Title")

For i = 0 To oTotalDict.Count - 1
	''' Now you can open each part and edit it
	''' or you could open the drawings of those parts
	''' or you could make a new Sub() which handles all sorts of stuff
	''' like making a partslist by scratch
	''' 
	''' oTotalDict.Keys(i) 		hold a stringvalue that looks like this: " C:\Inventor Files\Project X\FileName.iam"
	''' oTotalDict.Values(i) 	holds the TOTAL quantity of that part or assembly in the Main assembly (the one you have open right now)
	''' 
Next

Trace.WriteLine("***************** END ********************")

End Sub


Sub RecurseBOMRow(oBOMRow As BOMRow, oTotalDict As Dictionary(Of String, Integer), newParentQTY As Integer)
	'Trace.WriteLine("START of RecurseBOMRor for: " & oBOMRow.ComponentDefinitions.Item(1).Document.FullDocumentName & "QTY = " & oBOMRow.TotalQuantity & " Parent = " & newParentQTY)
	ParentQTY = oBOMRow.TotalQuantity 													' Set a new ParentQTY amount. When first encountered newParentQTY is 1
	For Each oBOMRow In oBOMRow.ChildRows
		Dim oCompDef As ComponentDefinition
			oCompDef = oBOMRow.ComponentDefinitions.Item(1)
		Call SetRowProps(oCompDef, oBOMRow.TotalQuantity, oTotalDict, newParentQTY) 	' Set the oTotalDict Key and Value for this object with the newParent QTY(should be 1 at first run.)
		If Not oBOMRow.ChildRows Is Nothing 											' Ooooh. Assembly.
			ParentQTY = oBOMRow.TotalQuantity 											'Now we;re looking in the row of the assembly in the assembly. The current value is just the value in that parent. We still need multiplication
			newnewParentQty = ParentQTY * newParentQTY 									'We're a couple of layers in now. We still hold newParentQTY from the current Parent. Parent QTY is th current value and newnewParent is the multiplication of those 2
			'Trace.WriteLine("DIGGIN DEEPER --: " & oBOMRow.ComponentDefinitions.Item(1).Document.FullDocumentName & " QTY = " & oBOMRow.TotalQuantity &" Parent = " & ParentQTY & " newParent = " & newParentQTY & " newnewParent = " & newnewParentQty )
			Call RecurseBOMRow(oBOMRow, oTotalDict, newnewParentQty)
		End If
	Next
End Sub

Sub SetRowProps(oCompDef As ComponentDefinition, QTY As Integer, oTotalDict As Dictionary(Of String, Integer), ParentQTY As Integer)
	'Trace.WriteLine("START SetRowProps for " & oCompDef.Document.FullDocumentName & " QTY is: " & QTY & " Parent = " & ParentQTY )
	Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
	Dim CompFileNameOnly As String
	Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
	CompFileNameOnly = CompFullDocumentName.Substring(index + 1)
	If oTotalDict.ContainsKey(CompFullDocumentName) = True Then
		KeyValue = oTotalDict(CompFullDocumentName)
		'Trace.WriteLine("EXISTING KEY. CURRENT QTY = " & KeyValue)
		QTY = QTY * ParentQTY
		' Trace.WriteLine("ADDING: " & QTY)
		oTotalDict(CompFullDocumentName) = QTY + KeyValue
		' Trace.WriteLine("NEW QTY = " & oTotalDict(CompFullDocumentName))
	Else
		oTotalDict(CompFullDocumentName) = QTY * ParentQTY
		'Trace.WriteLine("NEW KEY. QTY = " & oTotalDict(CompFullDocumentName))
	End If
End Sub


 

 

@Curtis_Waguespack

@bradeneuropeArthur 

 

 

I know this question gets asked very often and I see your input a lot. Here's something I made that I think you guys will like a lot.

 

 

Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below.

___________________________

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Technology Administrators


Autodesk Design & Make Report