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.
___________________________Solved! Go to Solution.
Solved by machiel.veldkamp. Go to Solution.
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.
Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below.
___________________________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.
___________________________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.
___________________________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
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.