Quantity in assembly

Quantity in assembly

inventor4578
Advocate Advocate
3,943 Views
18 Replies
Message 1 of 19

Quantity in assembly

inventor4578
Advocate
Advocate

Hi !

I make 3 machines in Inventor.

The 3 machines have some pieces in common.

 

The file tree is like this :

 

- MACHINE1.iam

     - Subassembly1.iam (Common)

     - Part1.ipt  (Common)

     - Part2.ipt  (Common)

Part3.ipt

Part4.ipt

Part5.ipt

........

- MACHINE2.iam

     - Subassembly1.iam (Common)

     - Part1.ipt  (Common)

     - Part2.ipt  (Common)

Part4.ipt

Part5.ipt

Part6.ipt

........

- MACHINE3.iam

     - Subassembly1.iam (Common)

     - Part1.ipt  (Common)

     - Part2.ipt  (Common)

Part7.ipt

Part8.ipt

Part9.ipt

........

 

 

In the drawing of common parts i need to get the TOTAL (in the 3 machines) quantity of parts. Like this table for example :

 

Machine 1 : 10x

Machine 2 : 0x

Machine 3 : 5x

 

The goal : When the manufacturer have to build bart, they get the by machine, and the TOTAL quantity.

 

How to manage this ?

 

Thank you very much,

Best regards.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 Likes
Accepted solutions (2)
3,944 Views
18 Replies
Replies (18)
Message 2 of 19

theo.bot
Collaborator
Collaborator

You can use The "parts only" bom view from your top assembly. This will give you the total of component from all Assemblies and there sub assemblies. By setting the rigth BOM structure for each part or assembly you will get a correct component list.

 

Here is some reference: About the BOM Structure | Inventor 2022 | Autodesk Knowledge Network

0 Likes
Message 3 of 19

inventor4578
Advocate
Advocate

Hi, thanks for reply.

Yes it can work, but i would like to have only the quantity of the part of the drawing (i have 1 drawing by 1 part).

And the quantity have to be attribute to each machine.

0 Likes
Message 4 of 19

theo.bot
Collaborator
Collaborator

I see, There is no direct way to get that info. So you simply need to store that machine and QTY info from the BOM view into a property or external source. On the drawing you can display that info into a table or any other text object. I would avoid this info on a drawing and store such info in PDM / ERP systems. To keep the data up to date on each drawing will be very hard. 

Message 5 of 19

GosponZ
Collaborator
Collaborator

We do use total qty, but not very smart way.  Try this one, but remember Library parts can't be count as total qty.

Sub Main
'Get current document
doc = ThisDoc.Document
Dim oAssyDef As AssemblyComponentDefinition = doc.ComponentDefinition
'Get the BOM object
Dim oBOM As BOM = oAssyDef.BOM
'enable the Parts Only View
oBOM.PartsOnlyViewEnabled = True
'Get the Parts Only view of the BOM
Dim oBOMViewPO As BOMView = oBOM.BOMViews.Item("Parts Only")
'declare variable for each BOM row.
Dim oBOMRowPO As BOMRow

'For each row in the Parts Only BOM, do the following
For Each oBOMRowPO In oBOMViewPO.BOMRows
    'Set a reference to the primary ComponentDefinition of the row
    Dim oCompDef As ComponentDefinition = oBOMRowPO.ComponentDefinitions.Item(1)
    
    'get the full filename associated to the component in the row. ex: c:\temp\part1.ipt
    Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
    Dim CompFileNameOnly As String
    'get the location of the last backslash
    Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
    'get the filename only from the full filename
    CompFileNameOnly = CompFullDocumentName.Substring(index+1)
    
    'MessageBox.Show(CompFileNameOnly)
    
    'get the Qty value in the current row
    Dim Qty As String = oBOMRowPO.TotalQuantity
    
    'check to see if the component is a library part, cc part or read only.
    Dim IsLibCCReadonly As Boolean = LibCCReadonlyChecker(CompFullDocumentName)
    
    'if the file is NOT a library part, cc part or read only.
    If IsLibCCReadonly = False Then
        'set following custom iproperty to equal the QTY from the row
        iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = Qty
    End If
Next

'at this time, the qty value for all parts have been copied to the custom property.
'next, the following code will cycle through only the subassemblies.

'if the Structured BOM view is enabled then...
If oBOM.StructuredViewEnabled Then
    'If show First Level is set then turn it off. This will set it to All Levels
    If oBOM.StructuredViewFirstLevelOnly Then
        oBOM.StructuredViewFirstLevelOnly = False
    End If
Else
    'enable the Structured BOM view
    oBOM.StructuredViewEnabled = True
    'set the FirstLevelOnly to false therefore make it All Levels
    oBOM.StructuredViewFirstLevelOnly = False
End If

'Get the Structured view of the BOM
Dim oBOMViewStruc As BOMView = oBOM.BOMViews.Item("Structured")
'declare variable for each BOM row.
Dim oBOMRowStruc As BOMRow
'Create a blank array(list). This will be used to store a list of all subassemblies for comparing if the subassembly already exist.
Dim arrSubAssemblyList As New ArrayList

'call a subroutine to cycle through the structured BOM. It will need the collection of rows, the subassembly list, and 1 is the initial parentqty.
Call QueryBOMRowProperties(oBOMViewStruc.BOMRows, arrSubAssemblyList, 1)

End Sub

Private Sub QueryBOMRowProperties(oBOMRows As BOMRowsEnumerator, arrSubAssembly As ArrayList, oParentQty As Integer)

'declare a incrementer variable
Dim i As Long
'for each row in the structured BOM
For i = 1 To oBOMRows.Count
    'get the row based on the incrementer
    Dim oBOMRowStruc As BOMRow = oBOMRows.Item(i)
    'get the component definition assocated with the row
    Dim oCompDef As ComponentDefinition = oBOMRowStruc.ComponentDefinitions.Item(1)
    Dim oQty As Integer
    
    'If the component is an assembly and it's bom structure is Normal then do the following. else do nothing
    If TypeOf oCompDef Is AssemblyComponentDefinition And oCompDef.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then
            'get the full filename associated to the component in the row. ex: c:\temp\subassembly.iam
            Dim CompFullDocumentName As String = oCompDef.Document.FullDocumentName
            Dim CompFileNameOnly As String
            'get the location of the last backslash
            Dim index As Integer = CompFullDocumentName.LastIndexOf("\")
            'get the filename only from the full filename
            CompFileNameOnly = CompFullDocumentName.Substring(index+1)
            'MessageBox.Show(CompFileNameOnly)
            
            'get the qty of the row and multiply by the parent qty.
            oQty = oBOMRowStruc.ItemQuantity * oParentQty
            
            'create a variable that will be used to get the qty of the subassembly if it was used elsewhere
            Dim additionalQty As Integer = 0
            'if the subassembly list is not empty then...
            If arrSubAssembly.Count <> 0 Then
                'create a counter. this will be used to determine which item in the subassembly array (list) when it finds a match.
                'this counter will be used to edit that item with the new qty.
                Dim counter As Integer = 0
                'for each item in the subassembly array (list) starting at 0 (first item) to last item
                For j As Integer = 0 To arrSubAssembly.Count-1
                    'get the location of the colon
                    Dim commaindex As Integer = arrSubAssembly(j).indexof(":")
                    'get just the file name
                    Dim CompName As String = arrSubAssembly(j).substring(0,commaindex)
                    
                    'if the file name of the current row matches the current item in the subassembly array (list) then...
                    If CompName = CompFileNameOnly Then
                        'set the additional qty to the qty found in the subassembly array (list)
                        additionalQty = arrSubAssembly(j).substring(commaindex+1)
                        'set the counter equal to the item in the subassembly array (list)
                        counter = j
                        'since a match is found, we need to exit the for loop so that counter no longer increments.
                        'so Set j To the number of items in the subassembly array. this will exit out the for loop.
                        j = arrSubAssembly.Count
                    Else
                        'increase the counter
                        counter += 1
                    End If
                Next
                
                'if additional qty was not changed then there was no match. It will be a new item in the subassembly array (list)
                If additionalQty = 0 Then
                    'add the subassambly to the subassembly array (list)
                    arrSubAssembly.Add(CompFileNameOnly & ":" & oQty)
                Else
                    'if it did find a match, then update the qty for that item in the subassembly array (list)
                    arrSubAssembly(counter) = CompFileNameOnly & ":" & oQty + additionalQty
                End If
            Else
                'add the first subassembly to the list. It will add the filename and the qty separated by a colon. ex. subassembly.iam:2
                arrSubAssembly.Add(CompFileNameOnly & ":" & oQty)
            End If
            
            'check to see if the component is a library part, cc part or read only.
            Dim IsLibCCReadonly As Boolean = LibCCReadonlyChecker(CompFullDocumentName)
            
            'if the file is NOT a library part, cc part or read only.
            If IsLibCCReadonly = False Then
                'set following custom iproperty to equal the QTY from the row plus the additional qty value
                iProperties.Value(CompFileNameOnly, "Custom", "PartQty") = oQty + additionalQty
            
                'Recursively iterate child rows if present.
                If Not oBOMRowStruc.ChildRows Is Nothing Then
                    'recall the subroutine, push the childrows of the sub, sub assembly array (list), and the qty of the subassembly
                    Call QueryBOMRowProperties(oBOMRowStruc.ChildRows, arrSubAssembly, oQty)
                End If
            End If
        End If
    Next
End Sub

Private Function LibCCReadonlyChecker(filename As String) As Boolean
' Get the active project
Dim oProject As DesignProject = ThisApplication.DesignProjectManager.ActiveDesignProject
' Get all the library paths
Dim oLibraryPaths As ProjectPaths = oProject.LibraryPaths
Dim oLibraryPath As ProjectPath

'for each library path in the list of all library paths
For Each oLibraryPath In oLibraryPaths
    'get the library path
    Dim oLibs As String = oLibraryPath.Path
    'if the file is in a library path then Return True
    If filename.Contains(oLibs) = True Then
        Return True
    End If
Next

'if the file is in the CC location then Return True
If filename.Contains(oProject.ContentCenterPath) = True Then
    Return True
End If

'get read only status
Dim File_Attr As Long = System.IO.File.GetAttributes(filename)
'if the file is readonly or readonly and archieve then Return True
If File_Attr = 1 Or File_Attr = 33 Then
    Return True
End If

'return False if it's not a library, CC or a Readonly part.
Return False

End Function

Message 6 of 19

WCrihfield
Mentor
Mentor
Accepted solution

OK, so you have a drawing of a part, and you want to show on that drawing how many of this part are within these three other assembly's, right?  There are likely many ways to do this, but likely none of them are going to be as convenient as you would like, because its complicated to do manually, so that complication level is going to multiply when code gets is involved.  And code 'might' be the best automation tool here.

 

First we have to get those quantities.  There are so many variables involved in this task, especially when the task is remote, it's hard to ask about them all.  In this code, I would need to uniquely identify these 3 assemblies we are going to search through, one way or another.  I'm just thinking in the most basic terms here and going to suggest manually entering (or cut/paste) those full file names into the start of the code.  Next we need to know what we are searching for within each of them.  There are many ways of identifying a component or part document within an assembly.  I'll just choose to use the full file name of the Part in my example below.

This doesn't even try to use the BOM, or avoid content center stuff, it simply opens each listed assembly file, then searches through it for components that represent the Part file name specified, then adds 1 to the quantity for each one it finds.

Sub Main
	Dim oAssemblyFiles As New List(Of String)
	oAssemblyFiles.Add("C:\Temp\Machine 1.iam")
	oAssemblyFiles.Add("C:\Temp\Machine 2.iam")
	oAssemblyFiles.Add("C:\Temp\Machine 3.iam")

	oPartFile = "C:\Temp\Part 5.ipt"

	'create a variable to hold the quantity
	Dim oQuantity As New List(Of Integer)

	For Each oName In oAssemblys
		Dim oAsmQuantity As Integer = 0
		Dim oADoc As AssemblyDocument
		If System.IO.File.Exists(oName) Then
			oADoc = ThisApplication.Documents.Open(oName, False)
		Else
			MsgBox("Could not find that file.  Skipping to next file name.", vbExclamation, "iLogic")
			Continue For
		End If
		If IsNothing(oADoc) Then Exit Sub
		oAllOccs = oADoc.ComponentDefinition.Occurrences
		
		'run our custom Sub routine below
		StepDown(oAllOccs, oPartFile, oAsmQuantity)
		
		oQuantity.Add(oAsmQuantity)
'		MsgBox("In this assembly:" & vbCrLf & oName & vbCrLf & _
'		"we found " & oAsmQuantity & " of the specified Part.", vbInformation, "iLogic")
	Next
	
	'now our oQuantity list should contain the quantities of the specified Part in each listed assembly
	For n As Integer = 1 To oAssemblyFiles.Count
		For q As Integer = 1 To oQuantity.Count
			MsgBox("In the assembly:" & vbCrLf & oAssemblyFiles.Item(n) & vbCrLf & _
			"we found " & oQuantity.Item(q) & " of the specified Part.", vbInformation, "iLogic")
		Next
	Next
End Sub

Sub StepDown(oComps As ComponentOccurrences, oPartName As String, ByRef oAsmQuantity As Integer)
	For Each oComp As ComponentOccurrence In oComps
		Try
			If oComp.Definition.Document.FullFileName = oPartName Then
				oAsmQuantity = oAsmQuantity + 1
			End If
		Catch
		End Try
		If TypeOf oComp.Definition Is AssemblyComponentDefinition Then
			StepDown(oComp.Definition.Occurrences, oPartName, oAsmQuantity)
		End If
	Next
End Sub

A more efficient process might have been to use something like the following:

oComp = ComponentOccurrences.ItemByName("occurrenceName1:1")
oCount = ComponentOccurrences.AllLeafOccurrences(oComp).Count

, but that needs you to specify a component name, which is often undesirable since they are usually auto-renamed.

You could have found the first component in the assembly of that Part, then used that component in that line, but that also involves a process which usually includes loops.

 

 

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 19

cadman777
Advisor
Advisor

Guys,

Can I hijack this thread for a second?
Can you show me the code that finds the BOM 'total quantity' of FrameGenerator parts?

I've tried to do that but can't figure out how to get my rule to see that iProperty from the top-level assembly.

It can see custom parts, but not ContentCenter parts.

Thanx...

... Chris
Win 7 Pro 64 bit + IV 2010 Suite
ASUS X79 Deluxe
Intel i7 3820 4.4 O/C
64 Gig ADATA RAM
Nvidia Quadro M5000 8 Gig
3d Connexion Space Navigator
0 Likes
Message 8 of 19

A.Acheson
Mentor
Mentor
Accepted solution

Here is a post in how to identify a document is referenced to frame generator addin. It uses the has interest method. If you look in the API help you will see other add ins reference there also. I would suggest starting a new thread as it would be different to this threads objective. 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 9 of 19

cadman777
Advisor
Advisor

Thanx Alan, appreciate it. That looks like it may make life easier for this rule. Also, Joel has a rule that changes the BaseUnit in FG parts, which is something I've been wanting to do. So I got 2 solutions in 1 from that forum thread!

 

I also figured out that the way my rule is presently written, it looks at the DisplayName instead of the 'Part Number'.  So I'm going to change that and see how the rule runs. Maybe that'll fix it.

 

Little by little I'm learning how to do this.

It's noway as easy to do as Grasshopper's VisualMacro system, but at least I'm getting the hang of it.

 

Cheers...

... Chris
Win 7 Pro 64 bit + IV 2010 Suite
ASUS X79 Deluxe
Intel i7 3820 4.4 O/C
64 Gig ADATA RAM
Nvidia Quadro M5000 8 Gig
3d Connexion Space Navigator
Message 10 of 19

inventor4578
Advocate
Advocate
I've got this error :

Error in rule: count, in document: ASSY1.iam
Object reference not set to an instance of an object.
0 Likes
Message 11 of 19

WCrihfield
Mentor
Mentor

I think I see the problem.  I changed the name of the variable at the start of the code, for the list of assembly names, from "oAssemblys" to "oAssemblyFiles", then forgot to copy that changed variable name down to the line of code where it is being used to start the main loop.  This line of code, near the top:

For Each oName In oAssemblys

needed to be updated/changed to this:

For Each oName In oAssemblyFiles

 But, apparently I did remember to copy it down into 2 places within the final report messages loop, after the main loop.

See if that fixes the rule for you.

Also, if you would rather find &/or identify these assemblies & parts differently, just be as detailed as possible about the specific needs/requirements/wants of the task, because code generally needs to be very specific to work.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 12 of 19

inventor4578
Advocate
Advocate
Hi !
It run now !
The result : It count only 2 of the 3 assembly.
The resultat of the 2 have mistake, because it show always "In the assembly ASSY.iam" for all counting (Always it show the same assembly path but the count is good). It is just a presentation error in text i think.

The error for the last assembly :

"Error in rule: count, in document: ASSY2.iam

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"
0 Likes
Message 13 of 19

WCrihfield
Mentor
Mentor

OK.  The 2 tiered loop at the end, just for reporting the results, apparently wasn't counting up each time, because I forgot to add 1 to the counter after each loop.  I also did not include any feedback in the Catch part of the Try...Catch block where it is trying to check the Component.Definition.Document.FullFileName against the specified part file name, so if it was failing, it was just continuing without adding any quantity and without any explanation.

 

I changed the regular List object at the beginning to a Dictionary object, so that each item within can hold 2 things, instead of just one, and each pair will be linked together.  (Might have been able to use a NameValueMap here instead, but they can be odd to work with.)  The 'Key' of each entry/pair in the dictionary is the full file name of an assembly to be searched.  The Value of each entry/pair will represent the quantity of the part we find in that assembly.  The Value is initially set to 0 (zero).  Then I use a single loop at the end to report the individual resulting quantity for each assembly, with that assembly's name in the message.  Instead of this loop showing a message 3 times, we could also write all 3 results to a single String message, then show that one message at the end, if that would work better for you.  Then within that custom Sub routine, I got rid of the Try...Catch block, and just used a couple more logical steps with If...Then statements to handle the count/quantity task.  I also added some extra comment lines in there, since I changed the code, to help you follow what's going on.  I hope these changes fix the problems you were having.

Here's the new code:

Sub Main
	'specify full file name (path, file name, & file extension)
	'of the Part file to find within these assemblies
	oPartFile = "C:\Temp\Part 5.ipt"
	
	'list of name - value pairs
	'name = assembly full file name (path, name, & file extension)
	'value = 0 (zero) to start, will be filled in by quantity of the part found within
	Dim oPairs As New Dictionary(Of String, Integer)
	oPairs.Add("C:\Temp\Machine 1.iam", 0)
	oPairs.Add("C:\Temp\Machine 2.iam", 0)
	oPairs.Add("C:\Temp\Machine 3.iam", 0)
	
	For Each oPair As KeyValuePair(Of String, Integer) In oPairs
		'create a variable to represent this AssemblyDocument
		Dim oADoc As AssemblyDocument
		
		'make sure this file can be found
		If System.IO.File.Exists(oPair.Key) Then
			'it was found, so try to open it invisibly (in the background)
			oADoc = ThisApplication.Documents.Open(oPair.Key, False)
		Else
			'it was not found, so notify user then skip to next assembly file name
			MsgBox("Could not find that file.  Skipping to next file name.", vbExclamation, "iLogic")
			Continue For 'this skips to next item in loop
		End If
		'double check that we have now assigned a value to this variable
		If IsNothing(oADoc) Then Exit Sub
			
		'get this assembly's ComponentOccurrences so we can loop through them
		oAllOccs = oADoc.ComponentDefinition.Occurrences
		
		'create a quantity variable to pass to our custom Sub routine
		Dim oQty As Integer = 0
		
		'run our custom Sub routine below
		StepDown(oAllOccs, oPartFile, oQty)
		
		'set the returned quantity to our oPair's Value
		'oPair.Value = oQty 'won't work, because Value is ReadOnly
		oPairs.Item(oPair.Key) = oQty 'this will work, not read only
		
'		MsgBox("In this assembly:" & vbCrLf & oPair.Key & vbCrLf & _
'		"we found " & oPair.Value & " of the specified Part.", vbInformation, "iLogic")
	Next
	
	'now our oQuantity list should contain the quantities of the specified Part in each listed assembly
	For Each oPair As KeyValuePair(Of String, Integer) In oPairs
		MsgBox("The following assembly file:" & vbCrLf & _
		oPair.Key & vbCrLf & _
		"Contained the following quantity of components representing the specified part:" & vbCrLf & _
		oPair.Value, vbInformation, "iLogic")
	Next
End Sub

Sub StepDown(oComps As ComponentOccurrences, oPartName As String, ByRef oQty As Integer)
	For Each oComp As ComponentOccurrence In oComps
		If oComp.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
			Dim oPDoc As PartDocument = oComp.Definition.Document
			If oPDoc.FullFileName = oPartName Then
				oQty = oQty + 1
			End If
		End If
		If TypeOf oComp.Definition Is AssemblyComponentDefinition Then
			StepDown(oComp.Definition.Occurrences, oPartName, oQty)
		End If
	Next
End Sub

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 14 of 19

inventor4578
Advocate
Advocate

Hi, and thank you for reply!
Now i've got this error :

Error Message :
"Error in rule: count, in document: PART_TEST.ipt
Collection was modified; enumeration operation may not execute."

More info:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
at LmiRuleScript.Main()
at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

0 Likes
Message 15 of 19

WCrihfield
Mentor
Mentor

Since I don't have any use for this code myself, and didn't have a file set to test it on, so I haven't been testing the codes locally, which often leads to unforeseen errors.  So...this time I created a folder, created three new assembly files with varying quantities of a certain test part file in them, and recorded the full file names of the part and all three assemblies to use in a local test scenario.  The previous code did not like the one line where I changed the value of the key/value pair while looping through the dictionary.  This behavior seemed to restrictive, so I switched to using a NameValueMap instead, to store the names and quantities, which then worked in my tests without any errors.  However, to simplify I then switched back to using a regular List again, then decided to record a 'Report' String as I loop through the three assemblies to keep a running tab on the findings as it progresses, instead of using another loop at the end to re-assemble the data, and this works out much smoother and simpler.  I also included a couple of important lines of code, that I couldn't believe I left out before...lines to dismiss those assembly documents after opening and inspecting them.  I also switched my custom reference routine from a Sub to a Function, because that better matches what we are using it for (to Return data).

 

Here is the new version of the code that was working flawlessly for me in my tests.

 

Sub Main
	'specify full file name (path, file name, & file extension)
	'of the Part file to find within these assemblies
	oPartFile = "C:\Temp\Part 5.ipt"
	
	'list of assembly full file names (path, name, & file extension)
	Dim oAsmFiles As New List(Of String)
	oAsmFiles.Add("C:\Temp\Machine 1.iam")
	oAsmFiles.Add("C:\Temp\Machine 2.iam")
	oAsmFiles.Add("C:\Temp\Machine 3.iam")
	
	Dim oReport As String
	Dim oTotalQty As Integer = 0
	For Each oAsmFile In oAsmFiles
		Dim oADoc As AssemblyDocument
		If System.IO.File.Exists(oAsmFile) Then
			oADoc = ThisApplication.Documents.Open(oAsmFile, False)
		Else
			MsgBox("Could not find that file.  Skipping to next file name.", vbExclamation, "iLogic")
			Continue For 'skips to next oAsmFile
		End If
		If IsNothing(oADoc) Then Exit Sub
		oAllOccs = oADoc.ComponentDefinition.Occurrences
		Dim oQty As Integer = StepDown(oAllOccs, oPartFile)
		oTotalQty = oTotalQty + oQty
		oReport = oReport & "Assembly:  " & oAsmFile & vbCrLf & "Quantity:  " & oQty & vbCrLf & vbCrLf
		'releases the reference to those invisibly opened documents so they can be cleaned up
		oADoc.ReleaseReference
		'oADoc.Close(True)
	Next
	ThisApplication.Documents.CloseAll(True) 'True = only close unreferenced documents
	oReport = oReport & "Total Quantity:  " & oTotalQty
	MsgBox(oReport, vbInformation, "iLogic")
End Sub

Function StepDown(oComps As ComponentOccurrences, oPartName As String) As Integer
	Dim oQuantity As Integer = 0
	For Each oComp As ComponentOccurrence In oComps
		If oComp.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
			Dim oPDoc As PartDocument = oComp.Definition.Document
			If oPDoc.FullFileName = oPartName Then
				oQuantity = oQuantity + 1
			End If
		End If
		If TypeOf oComp.Definition Is AssemblyComponentDefinition Then
			oQuantity = oQuantity + StepDown(oComp.Definition.Occurrences, oPartName)
		End If
	Next
	Return oQuantity
End Function

 

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 16 of 19

inventor4578
Advocate
Advocate

It's working great ! Amazing.

Is it possible to add factor for counting ?

If i have 5 machine 1 / 7 machine 2 and 3 machine 3 for example ?

 

Thank you very much again!

 

0 Likes
Message 17 of 19

WCrihfield
Mentor
Mentor

The short answer most likely, yes.  How difficult/complicated making those changes to the code will be depends on how & when you want to specify/supply those multiplication factors, and how you want the end result to be presented.  The multiplication factor will need to be somehow kept together with the assembly it was meant for from beginning to end, so it will likely mean using more multi-value type variables to hold the related bits of data together.

So far this code doesn't seem very user friendly to me yet, because it is not usually a good situation when you have to manually edit the rule before every time you want to run it.  If needed, we may incorporate better user interaction tools to help avoid the need to edit the code each time.  Things like a file dialog to select the part or assembly files, and/or getting the part from an active drawing of the part and/or using some InputBox or InputListBox type routines, or using an Excel sheet, etc.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 18 of 19

inventor4578
Advocate
Advocate

Ok thank you very much.

Can be great in the code, like this :

 

Dim oAsmFiles As New List(Of String)
oAsmFiles.Add("MACHINE1.iam") * 10
oAsmFiles.Add("MACHINE2.iam") * 5
oAsmFiles.Add("MACHINE3.iam") * 3

0 Likes
Message 19 of 19

WCrihfield
Mentor
Mentor

OK.  I think I have something that will work that way for you that way.  I chose to use a NameValueMap this time, so I could store the order quantity multiplier with the assembly it is meant for.  Then I also incorporated a few InputBox functions to make the data entry/edit changes quicker & easier, without having to directly edit the rule code itself.  It uses a Do...Loop type of loop, that will exit the loop when you enter an empty assembly name and/or an empty order quantity.  This allows you to enter as many assemblies and order quantities as you want.  I tested this on my sample files and it worked as expected, so I hope it also work for you.

Here is the updated code:

 

Sub Main
	'get Part file name from user
	oPartFile = InputBox("Enter the 'Full File Name' (path, name, & file extension)" & vbCrLf & _
	"of the Part file you want to find the quantity of within multiple assemblies.", "Part File To Find", "")
	If String.IsNullOrEmpty(oPartFile) Then Exit Sub 'nothing was entered, so exit rule 
	
	'NameValueMap to hold Name/Value pairs (Assembly file name, order quantity)
	Dim oAsmFiles As NameValueMap = ThisApplication.TransientObjects.CreateNameValueMap
	
	Dim oEmpty As Boolean = False
	Do Until oEmpty = True
		'get assembly file name from user
		oFileName = InputBox("Enter the 'Full File Name' (path, name, & file extension)" & vbCrLf & _
		"of an Assembly file you want to search for the part within.", "Assembly File To Search Within", "")
		'get order quantity from user
		oNum = InputBox("Enter 'Order Quantity' for that Assembly.", "Order Quantity", "1")
		'check returned values, to make sure not empty
		If String.IsNullOrEmpty(oFileName) Or String.IsNullOrEmpty(oNum) Then
			oEmpty = True
		Else
			oAsmFiles.Add(oFileName, CInt(oNum))
		End If
	Loop
	
	Dim oReport As String
	Dim oTotalQty As Integer = 0
	Dim i As Integer = 1 'for looping through NameValueMap
	For Each oItem In oAsmFiles 'oItem Type should not be defined, simply a placeholder here
		oAsmFile = oAsmFiles.Name(i)
		Dim oOrderQuantity As Integer = oAsmFiles.Value(oAsmFiles.Name(i))
		Dim oADoc As AssemblyDocument
		If System.IO.File.Exists(oAsmFile) Then
			oADoc = ThisApplication.Documents.Open(oAsmFile, False)
		Else
			MsgBox("Could not find that file.  Skipping to next file name.", vbExclamation, "iLogic")
			Continue For 'skips to next oAsmFile
		End If
		If IsNothing(oADoc) Then Exit Sub
		oAllOccs = oADoc.ComponentDefinition.Occurrences
		Dim oQty As Integer = (StepDown(oAllOccs, oPartFile) * oOrderQuantity)
		oTotalQty = oTotalQty + oQty
		oReport = oReport & "Assembly:  " & oAsmFile & vbCrLf & "Quantity:  " & oQty & vbCrLf & vbCrLf
		'releases the reference to those invisibly opened documents so they can be cleaned up
		oADoc.ReleaseReference
		'oADoc.Close(True)
		i = i + 1
	Next
	ThisApplication.Documents.CloseAll(True) 'True = only close unreferenced documents
	oReport = oReport & "Total Quantity:  " & oTotalQty
	MsgBox(oReport, vbInformation, "iLogic")
End Sub

Function StepDown(oComps As ComponentOccurrences, oPartName As String) As Integer
	Dim oQuantity As Integer = 0
	For Each oComp As ComponentOccurrence In oComps
		If oComp.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
			Dim oPDoc As PartDocument = oComp.Definition.Document
			If oPDoc.FullFileName = oPartName Then
				oQuantity = oQuantity + 1
			End If
		End If
		If TypeOf oComp.Definition Is AssemblyComponentDefinition Then
			oQuantity = oQuantity + StepDown(oComp.Definition.Occurrences, oPartName)
		End If
	Next
	Return oQuantity
End Function

 

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)