Hi all.
I want to create an array that will store the iProperty Partnumber of each component in a reference model. The reference model is defined as the model used in a drawing view and the rule will be run from the drawing document.
Any help will be appreciated on this one.
Mike
Solved! Go to Solution.
Solved by WCrihfield. Go to Solution.
Hi @mikejones. I am not sure about the true scope of your task, or how you need to specify which view to process, so I wasn't sure how deep you wanted this to go. For instance, do you only want the rule to process the view if it directly references an assembly? Do you only want the part numbers of 'top level' assembly components in that assembly, or do you want it to go down into sub levels, and sub sub levels, etc? Do you only want one part number listed for each 'unique' component (even if multiple components reference same model file), or one for every component, even if there are 10 components referencing the same model file? Below is an example that lets you 'Pick' a view, then just processes the top level components that are not suppressed.
Sub Main
Dim oView As DrawingView = PickDrawingView
Dim oModel As Document = oView.ReferencedDocumentDescriptor.ReferencedDocument
Dim oPNList As New List(Of String)
If oModel.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then Exit Sub
Dim oAModel As AssemblyDocument = oModel
Dim oOccs As ComponentOccurrences = oAModel.ComponentDefinition.Occurrences
If oOccs.Count = 0 Then Exit Sub 'no components to process
For Each oOcc As ComponentOccurrence In oOccs
If oOcc.Suppressed Then Continue For
Dim oPN As String = iProperties.Value(oOcc.Name, "Project", "Part Number")
oPNList.Add(oPN)
Next
oMyPN = InputListBox("", oPNList, "", "Part Numbers")
End Sub
Function PickDrawingView(Optional oPrompt As String = vbNullString) As DrawingView
If oPrompt = "" Then oPrompt = "Select a Drawing View."
oObj = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, oPrompt)
If IsNothing(oObj) OrElse (TypeOf oObj Is DrawingView = False) Then Return Nothing
Dim oView As DrawingView = oObj
Return oView
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) 👍.
Wesley Crihfield
(Not an Autodesk Employee)
Thanks for the quick responce @WCrihfield .
This rule will only ever run on an assembly drawing and I want to get a complete list of all parts and sub assemblies referenced in it, however deep the tree goes. If a component occurs multiple times then I only need to reference it once.
It is going to give me a list of all the part and sub assembly drawings required for manufacturing purposes
Mike
OK. I have modified the code to iterate through the assembly document's 'AllReferencedDocuments', which reaches every level of the assembly. It is still possible though, that this does not include some documents, if every component, in every level that references that document has been suppressed. I am using an iLogic shortcut within the loop that was only made available in the 2021 product year, so if you are using an earlier version, we may have to change that to using API route, to get the iProperty value. Just let me know. I am just using an InputListBox to show you the resulting list of part numbers, but you can modify to do whatever you need with that list.
Sub Main
Dim oView As DrawingView = PickDrawingView
Dim oModel As Document = oView.ReferencedDocumentDescriptor.ReferencedDocument
Dim oPNList As New List(Of String)
If oModel.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then Exit Sub
Dim oAModel As AssemblyDocument = oModel
Dim oRefDocs As DocumentsEnumerator = oAModel.AllReferencedDocuments
If oRefDocs.Count = 0 Then Exit Sub
For Each oRefDoc As Document In oRefDocs
Dim SOP = StandardObjectFactory.Create(oRefDoc) 'Inventor 2021 or later only
Dim oPN As String = SOP.iProperties.Value("Project", "Part Number")
oPNList.Add(oPN)
Next 'oRefDoc
oMyPN = InputListBox("", oPNList, "", "Part Numbers")
End Sub
Function PickDrawingView(Optional oPrompt As String = vbNullString) As DrawingView
If oPrompt = "" Then oPrompt = "Select a Drawing View."
oObj = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, oPrompt)
If IsNothing(oObj) OrElse (TypeOf oObj Is DrawingView = False) Then Return Nothing
Dim oView As DrawingView = oObj
Return oView
End Function
Wesley Crihfield
(Not an Autodesk Employee)
That certainly gave me a complete list of all the files but now I want to filter out and ignore ones that have their BOM structure set to reference or phantom. So I need some code that does what is in red below.
For Each oRefDoc As Document In oRefDocs Dim SOP = StandardObjectFactory.Create(oRefDoc) 'Inventor 2021 or later only If the BOM type is normal or inseperable then Dim oPN As String = SOP.iProperties.Value("Project", "Part Number") oPNList.Add(oPN)
End If Next 'oRefDoc
Thanks for your help so far.
Mike
OK. Here you go. I think this should do the trick.
Sub Main
Dim oView As DrawingView = PickDrawingView
Dim oModel As Document = oView.ReferencedDocumentDescriptor.ReferencedDocument
Dim oPNList As New List(Of String)
If oModel.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then Exit Sub
Dim oAModel As AssemblyDocument = oModel
Dim oRefDocs As DocumentsEnumerator = oAModel.AllReferencedDocuments
If oRefDocs.Count = 0 Then Exit Sub
For Each oRefDoc As Document In oRefDocs
Dim oBOMSt As BOMStructureEnum = oRefDoc.ComponentDefinition.BOMStructure
If oBOMSt = BOMStructureEnum.kReferenceBOMStructure Or _
oBOMSt = BOMStructureEnum.kPhantomBOMStructure Then
Continue For 'skip to next oRefDoc in loop, if any
End If
Dim SOP = StandardObjectFactory.Create(oRefDoc) 'Inventor 2021 or later only
Dim oPN As String = SOP.iProperties.Value("Project", "Part Number")
oPNList.Add(oPN)
Next 'oRefDoc
oMyPN = InputListBox("", oPNList, "", "Part Numbers")
End Sub
Function PickDrawingView(Optional oPrompt As String = vbNullString) As DrawingView
If oPrompt = "" Then oPrompt = "Select a Drawing View."
oObj = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, oPrompt)
If IsNothing(oObj) OrElse (TypeOf oObj Is DrawingView = False) Then Return Nothing
Dim oView As DrawingView = oObj
Return oView
End Function
Wesley Crihfield
(Not an Autodesk Employee)
@WCrihfield you are a genius, that has done everything I needed it to do. Thank you so much
Mike
Hi Chris
This is part of a rule I'm developing for one of my manufacturing clients. It is basically a further development of an existing rule that creates a pdf and dxf file of a released drawing, and adds the drawing revision number as a suffix to the file names. Before creating the new files the rule also checks whether a previous version of the files exist and if so moves them into an archive folder. At the same time it will update the clients drawing register, which is an excel spreadsheet, with the relevant drawing information.
The new bit of code now determines whether the drawing is part of a manufacturing package and if it is then it will get all drawings required for manufacturing and put them into a folder that can be sent out for supply, hence the need for the list of normal and inseparable files. When manufacturing drawings are updated the code will also check all manufacturing packages for the same drawing and replace them with the new one.
Currently this is being done manually by my client through windows explorer and is very prone to errors; I'm personally against copies of files in multiple places but if the client is insisting on doing it this way who am I to argue? They have no cad software in house and no MRP or ERP systems in place so it very much a manual process that I'm trying to automate for them.
Hopefully that makes sense.
Mike
This message goes to @WCrihfield or anyone else that can help.
The solution offered by @WCrihfield worked great but I've recently realized it doesn't do what I want in all situations and that the 'AllReferencedDocuments' won't work if there are sub-assemblies in the file that are in as reference only; i.e. all of the parts in the reference sub-assembly are listed when they shouldn't be. Would it be possible to use the Parts Only BOM as the driver and ignore Purchased Parts from the list?
I've attached a Pack&Go sample file; 2023 version, and drawing that hopefully explains the situation better.
Any and all help really appreciated.
Mike
Hi @mikejones. I'm still using 2022.3.2, so I wouldn't be able to open your files, but using Parts only BOMView certainly sounds doable. To you want to keep the 'Pick View' functionality, or would you prefer to just have it work with the first view on the active sheet of the drawing? And is the 'InputListBox' thing working OK for you, or would you prefer to have the bulk of the code set-up as a separate Function which will return the List(Of String) object, since this is just part of a larger automation project?
Wesley Crihfield
(Not an Autodesk Employee)
Hi again @WCrihfield and thanks for replying.
Working from the first Base view on the sheet will work better for me if that's not too much trouble; just speeds up the whole process for me.
The Dim oPNList As New List(Of String) method is working for me currently, just some additional incorrect items being picked up in it. It would be good to get parts from a weldment assembly as well but they won't show up in the Parts Only BOM unless I change the weldment BOM structure from Inseperable to Normal which I'd rather not do. Is there a way around that problem?
The only parts I don't want in the list will be parts that are inside an assembly that has a BOM Structure of Reference and Parts that have a BOM Structure of anything other than Normal i.e. no Purchased, Phantom etc.
Mike
To avoid the weldment BOMStructure issue, we could just try doing the iteration of the assembly components directly, instead of using the Parts Only BOMView, and instead of using the AllReferendedDocuments routes. It's slightly less efficient, but certainly doable that way, I would just have to incorporate an extra List type variable for keeping track of component referenced documents that I've already processed, so I don't process the same ones multiple times. I have done that before several times in other solutions, so its not too bit a deal. I might also have to incorporate a separate recursive Sub routine, for digging down through all the levels, but I've done that before many times too, so no big deal there either. Getting the first base view on the active sheet shouldn't be a problem either. I would just have to start the code a bit more traditionally. No promises on timing, because I've got a few things going on at the same time, but I'll see what I can do.
Wesley Crihfield
(Not an Autodesk Employee)
Thank you.
I thought I'd help someone else out on the Inventor Forum as you were helping me out, what goes around comes around as they say.
I'm off skiing tomorrow for a week so I'm not in any rush for this, whenever you have time.
Mike
Hi @mikejones. I've got something for you to try out. It may look a bit intimidating, but I think it might work for you. I only put a few comments in there, because its already a fairly lengthy code, but if you need to ask about anything, please do. I'm not 100% sure if the Document object filter will work as planned now that ModelStates have complicated those references, but if not, we can try something else, like maybe FullFileName or FullDocumentName or something else unique about each one. Let me know how this works out for you.
Class ThisRule
Dim oDocs As List(Of Document) 'shared with all routines
Dim oPNList As List(Of String) 'shared with all routines
Sub Main
If ThisDoc.Document.DocumentType <> DocumentTypeEnum.kDrawingDocumentObject Then
MsgBox("A Drawing document must be active for this code to work. Exiting.", vbCritical, "")
Exit Sub
End If
Dim oDDoc As DrawingDocument = ThisDoc.Document
Dim oViews As DrawingViews = oDDoc.ActiveSheet.DrawingViews
If oViews.Count = 0 Then Exit Sub 'may want a feedback message or Log entry here.
Dim oBV As DrawingView
For Each oView As DrawingView In oViews
If oView.ViewType = DrawingViewTypeEnum.kStandardDrawingViewType Then
oBV = oView : Exit For
End If
Next 'oView
If IsNothing(oBV) Then Exit Sub 'may want a feedback message or Log entry here.
Dim oADoc As AssemblyDocument = oBV.ReferencedDocumentDescriptor.ReferencedDocument
Dim oOccs As ComponentOccurrences = oADoc.ComponentDefinition.Occurrences
oDocs = New List(Of Document) 'to initiate it
oPNList = New List(Of String) 'to initiate it
RecursivelyProcessComponents(oOccs)
oMyPN = InputListBox("", oPNList, "", "Part Numbers")
End Sub
Sub RecursivelyProcessComponents(oComps As ComponentOccurrences)
If IsNothing(oComps) OrElse oComps.Count = 0 Then Exit Sub
For Each oComp As ComponentOccurrence In oComps
Dim ProcessFurther As Boolean = ProcessComponent(oComp) 'run our other routine
If ProcessFurther = False Then Exit Sub
If oComp.SubOccurrences.Count > 0 Then
RecursivelyProcessComponents(oComp.SubOccurrences)
End If
Next
End Sub
Function ProcessComponent(oComp As ComponentOccurrence) As Boolean
If IsNothing(oComp) OrElse oComp.Suppressed Then Return False
'filter by BOMStructure values
'Note: BOMStructure of component can be different than its referenced document
If oComp.BOMStructure <> BOMStructureEnum.kNormalBOMStructure And _
oComp.BOMStructure <> BOMStructureEnum.kInseparableBOMStructure Then
Return False
End If
If oComp.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
If oComp.Definition.BOMStructure = BOMStructureEnum.kReferenceBOMStructure Then Return False
ElseIf oComp.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject Then
If oComp.Definition.BOMStructure <> BOMStructureEnum.kNormalBOMStructure Then Return False
End If
Dim oDoc As Document = oComp.Definition.Document
If oDocs.Contains(oDoc) Then Return False 'do not process the same document again
Dim SOP = StandardObjectFactory.Create(oDoc) 'Inventor 2021 or later only
Dim oPN As String = SOP.iProperties.Value("Project", "Part Number")
oPNList.Add(oPN)
oDocs.Add(oDoc)
Return True 'return True, so it will process any sub occurrances of this component
End Function
End Class
Wesley Crihfield
(Not an Autodesk Employee)
Hi @WCrihfield
Thanks for taking the time to generate the code for me.
No that I'm back from my holiday; great to get awayagain, I've run the code this morning but I get the following error on line 14
Object reference not set to an instance of an object.
This is referring to the line
If oBV.ViewType = DrawingViewTypeEnum.kStandardDrawingViewType Then
Do you have any idea why this is failing? I've tried changing the view type to projected aswell but that also fails with the same error.
Mike
Good morning @mikejones. I see my mistake. I should have used the 'oView' variable in that line, instead of the 'oBV' variable. The loop definition line is using the oView variable, so it will always have a value, while the oBV variable will not have a value until after that line, if the oView passes the test. So that line should have been:
If oView.ViewType = DrawingViewTypeEnum.kStandardDrawingViewType Then
I will fix that line in my code, so others can copy/paste it without the error being in there.
Wesley Crihfield
(Not an Autodesk Employee)
Thanks.
That makes sense now I think about it. I'll give it another try.
Mike
Hi again.
So the code now gets a base view ok and displays the InputListBox from the code below
oMyPN = InputListBox("", oPNList, "", "Part Numbers")
but, what I find is that if the base view is an assembly with just components it is fine but if it is an assembly file with sub assembly (BOM Normal) then it return an empty list i.e. it only returns a list if the Base View file reference is an assembly with part files only.
Any ideas?
Mike
I think the issue is with the code highlighted red below. I think as soon as a reference that has a BOM Structure that is not NORMAL or INSEPARABLE is found then the code exits if I've understood it correctly. I don't know how to fix it though if that is the issue.
Sub RecursivelyProcessComponents(oComps As ComponentOccurrences) If IsNothing(oComps) OrElse oComps.Count = 0 Then Exit Sub For Each oComp As ComponentOccurrence In oComps Dim ProcessFurther As Boolean = ProcessComponent(oComp) 'run our other routine If ProcessFurther = False Then Exit Sub'........This needs to process the next oComp rather than exit If oComp.SubOccurrences.Count > 0 Then RecursivelyProcessComponents(oComp.SubOccurrences) End If Next End Sub Function ProcessComponent(oComp As ComponentOccurrence) As Boolean If IsNothing(oComp) OrElse oComp.Suppressed Then Return False 'filter by BOMStructure values 'Note: BOMStructure of component can be different than its referenced document If oComp.BOMStructure <> BOMStructureEnum.kNormalBOMStructure And _ oComp.BOMStructure <> BOMStructureEnum.kInseparableBOMStructure Then Return False End If
Can't find what you're looking for? Ask the community or share your knowledge.