iLogic Qty rule not working on assemblies/parts with model states

iLogic Qty rule not working on assemblies/parts with model states

devonjohnson
Enthusiast Enthusiast
799 Views
5 Replies
Message 1 of 6

iLogic Qty rule not working on assemblies/parts with model states

devonjohnson
Enthusiast
Enthusiast

Hi,

 

We have been using an ilogic rule I originally found on this forum, I just tweaked it slightly to suit our needs.  With the introduction of the model states though it skips these files.  I have been adding in different snippets of code that I've found on here but nothing has worked so far.  I've just linked this field to our titleblock as well so its a bit more urgent and can't really wait for me to work it out myself.  I generally find all my answers on here but with model states being so new there doesn't seem to be many posts.

When this runs there aren't any errors but any parts/assemblies with model states aren't updated.  I assumed its possible to write to these parts as they're available for editing in the BOM.

 

Any help would be greatly appreciated!

 

Here's the code we are currently using:

 

Sub Main ()
	'Check to see if this document is an assembly.
	oDoc = ThisApplication.ActiveDocument
		If oDoc.DocumentType <> kAssemblyDocumentObject Then
		MessageBox.Show("This rule can only be run in an Assembly file - exiting rule...", "GDI iLogic")
		Return
		End If
	'If iProperties.Value("Project", "Project")=""
	'	oProj = InputBox("Change Project Name", "Project Name", iProperties.Value("Project", "Project"))
	'	iProperties.Value("Project", "Project")=oProj
	'End If

'get the project number of this assembly and use it to build the name of a custom property, i.e. "4100_QTY"
customPropertyName = "Total Qty"

	oQ=MessageBox.Show(customPropertyName, "Run Qty Rule",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question)
		If oQ=vbYes
		oDone()
		ElseIf oQ=vbNo
		Call oProject
		ElseIf oQ=vbCancel
		MessageBox.Show("Cancelled", "GDI iLogic", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1)
		Return
	End If
End Sub



Sub oDone
oCompDef = ThisDoc.Document.ComponentDefinition
openDoc = ThisDoc.Document
customPropertyName = "Total Qty"
'Open the document that inventor has in focus right now
    For Each docFile In openDoc.AllReferencedDocuments

	'FNamePos is getting the number of spaces that it takes to get to the 
    'very last back slash in the full file name of our document.         
        FNamePos = InStrRev(docFile.FullFileName, "\", -1)        
     
	'We can then take that number (position) and use it to cut off all of the 
    'file path that we don't need. In this case, it's the front of the path
    'that we're getting rid of, leaving us with just the file name.
        docFName = Mid(docFile.FullFileName, FNamePos + 1, Len(docFile.FullFileName) -FNamePos)
		        
        'Let's make sure that we can even change this part. If we can, then we'll continue. 
        If docFile.IsModifiable = True Then
            
            'Because you can only grab the occurrences from an assembly document
            'we need to fill up that empty AssemblyDocument container with an object
            'that we know is definitely an assembly document. Because that was one
            'of the first checks we made up there on this open document, we can safely
            'declare that assemblyDoc (Which is an AssemblyDocument) is equal to 
            ' openDoc (Which is just a regular old Document)             
            assemblyDoc = openDoc        
            
            'While we're at it, let's go on and define the empty ComponentDefinition container
            '(we named ours assemblyDef) with some sort of content. 
            assemblyDef = assemblyDoc.ComponentDefinition
            
            'Now we need to collect every instance of the document against
            'our open assembly and put them all inside of partQty. 
            partQty = assemblyDef.Occurrences.AllReferencedOccurrences(docFile)
           
	
                'Now that we have our collection of instances, we need to populate
                'our target iproperty with the total amount. 
                
                'Instead of just throwing that amount in there, let's make sure that
                'the value inside of the target iProperty isn't already equal to our count. 
                'If it is equal, then we don't have to change anything (which saves us time!),
                'but if it isn't equal then we will need to change it. 
                
                'The Try statement is here because of the next if statement ---
               
                'If we just compare the two values, there is a small chance that our target
                'iProperty is already set to something that is NOT a number, which would create
                'an error (as you can't compare numbers against things that aren't numbers). 
                'So, we TRY to complete that if statement, and if there is an error (The CATCH)
                'we just force that target to equal our part qty total. 
                Try
						If partQty.Count <>  iProperties.Value(docFName, "Custom", customPropertyName) Then                
						iProperties.Value(docFName, "Custom", customPropertyName) = partQty.Count
                    	End If                      
                Catch
						iProperties.Value(docFName, "Custom", customPropertyName) = partQty.Count
                End Try
        End If
    Next
'29/01/2016
'I added the following to create the value for the GA
'Some code automation in the Detailing environment was
'failing because it could not find a valid entry.
'This is a dummy field, and does not contribute to the rest of the inteligence of the rule.
			Try
				oASSYParam= iProperties.Value("Custom",customPropertyName)
              Catch
				iProperties.Value("Custom",customPropertyName) = "1"
					End Try
iLogicVb.UpdateWhenDone = True 
MessageBox.Show("Completed" & vbNewLine & ":-)", "Completed", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1)
End Sub

 

 

Thanks,
Devon Johnson

Inventor 2020
0 Likes
800 Views
5 Replies
Replies (5)
Message 2 of 6

JelteDeJong
Mentor
Mentor

Model states bring some problems (and solutions). I did write a blog post about this "Deep dive in model states and parameters API". I would not be surprised if the problem and solution that I described in that post can solve your problem. I made some changes in the oDone() function without being able to test if this is a solution. But you can give it a try.

 

    Sub Main()
        'Check to see if this document is an assembly.
        Dim oDoc = ThisApplication.ActiveDocument
        If oDoc.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
            MessageBox.Show("This rule can only be run in an Assembly file - exiting rule...", "GDI iLogic")
            Return
        End If
        'If iProperties.Value("Project", "Project")=""
        '	oProj = InputBox("Change Project Name", "Project Name", iProperties.Value("Project", "Project"))
        '	iProperties.Value("Project", "Project")=oProj
        'End If

        'get the project number of this assembly and use it to build the name of a custom property, i.e. "4100_QTY"
        Dim customPropertyName = "Total Qty"

        Dim oQ = MessageBox.Show(customPropertyName, "Run Qty Rule", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
        If oQ = vbYes Then
            oDone()
        ElseIf oQ = vbNo Then
            'Call oProject
        ElseIf oQ = vbCancel Then
            MessageBox.Show("Cancelled", "GDI iLogic", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1)
            Return
        End If
    End Sub



    Sub oDone()
        ' ---- here i used my function to get the factory document. ----
        Dim openDoc = ThisDoc.Document
        openDoc = GetFactoryDocument(openDoc)
        Dim oCompDef = openDoc.ComponentDefinition

        Dim customPropertyName = "Total Qty"
        'Open the document that inventor has in focus right now
        For Each docFile In openDoc.AllReferencedDocuments
            ' ---- not sure if getting factory document is needed here... ----
            docFile = GetFactoryDocument(docFile)

            'FNamePos is getting the number of spaces that it takes to get to the 
            'very last back slash in the full file name of our document.         
            Dim FNamePos = InStrRev(docFile.FullFileName, "\", -1)

            'We can then take that number (position) and use it to cut off all of the 
            'file path that we don't need. In this case, it's the front of the path
            'that we're getting rid of, leaving us with just the file name.
            Dim docFName = Mid(docFile.FullFileName, FNamePos + 1, Len(docFile.FullFileName) - FNamePos)

            'Let's make sure that we can even change this part. If we can, then we'll continue. 
            If docFile.IsModifiable = True Then

                'Because you can only grab the occurrences from an assembly document
                'we need to fill up that empty AssemblyDocument container with an object
                'that we know is definitely an assembly document. Because that was one
                'of the first checks we made up there on this open document, we can safely
                'declare that assemblyDoc (Which is an AssemblyDocument) is equal to 
                ' openDoc (Which is just a regular old Document)             
                Dim assemblyDoc = openDoc

                'While we're at it, let's go on and define the empty ComponentDefinition container
                '(we named ours assemblyDef) with some sort of content. 
                Dim assemblyDef = assemblyDoc.ComponentDefinition

                'Now we need to collect every instance of the document against
                'our open assembly and put them all inside of partQty. 
                Dim partQty = assemblyDef.Occurrences.AllReferencedOccurrences(docFile)


                'Now that we have our collection of instances, we need to populate
                'our target iproperty with the total amount. 

                'Instead of just throwing that amount in there, let's make sure that
                'the value inside of the target iProperty isn't already equal to our count. 
                'If it is equal, then we don't have to change anything (which saves us time!),
                'but if it isn't equal then we will need to change it. 

                'The Try statement is here because of the next if statement ---

                'If we just compare the two values, there is a small chance that our target
                'iProperty is already set to something that is NOT a number, which would create
                'an error (as you can't compare numbers against things that aren't numbers). 
                'So, we TRY to complete that if statement, and if there is an error (The CATCH)
                'we just force that target to equal our part qty total. 
                Try
                    If partQty.Count <> iProperties.Value(docFName, "Custom", customPropertyName) Then
                        iProperties.Value(docFName, "Custom", customPropertyName) = partQty.Count
                    End If
                Catch
                    iProperties.Value(docFName, "Custom", customPropertyName) = partQty.Count
                End Try
            End If
        Next
        '29/01/2016
        'I added the following to create the value for the GA
        'Some code automation in the Detailing environment was
        'failing because it could not find a valid entry.
        'This is a dummy field, and does not contribute to the rest of the inteligence of the rule.
        Try
            oASSYParam = iProperties.Value("Custom", customPropertyName)
        Catch
            iProperties.Value("Custom", customPropertyName) = "1"
        End Try
        iLogicVb.UpdateWhenDone = True
        MessageBox.Show("Completed" & vbNewLine & ":-)", "Completed", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1)
    End Sub

    Public Function GetFactoryDocument(doc As Document)
        If (doc Is Nothing) Then Return Nothing

        Dim documentType As DocumentTypeEnum = doc.DocumentType
        If (documentType = DocumentTypeEnum.kPartDocumentObject Or
            documentType = DocumentTypeEnum.kAssemblyDocumentObject) Then

            If (documentType = DocumentTypeEnum.kPartDocumentObject) Then
                Dim def As PartComponentDefinition = doc.ComponentDefinition
                If (def.IsModelStateMember) Then
                    Return def.FactoryDocument
                End If
            End If
            If (documentType = DocumentTypeEnum.kAssemblyDocumentObject) Then
                Dim def As AssemblyComponentDefinition = doc.ComponentDefinition
                If (def.IsModelStateMember) Then
                    Return def.FactoryDocument
                End If
            End If
            Return doc
        End If
        Return Nothing
    End Function

 

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

0 Likes
Message 3 of 6

rhasell
Advisor
Advisor

@devonjohnson 

Thanks for asking the question, been wanting to do the same, I will be following this closely.

Regards

 

Reg
2026.1
0 Likes
Message 4 of 6

devonjohnson
Enthusiast
Enthusiast

Thank you for your help, but unfortunatelly it still doesn't work (no errors).  When I include the 

docFile = GetFactoryDocument(docFile)

line after the "For Each" line, it changes all the quantites with model states to 0.   Without it, it doesn't change them at all.  I've only had a small amount of time to play around with it today but I will look more into it again next week and get back to you if I manage to get it working.

 

Your article was very helpful too!

 

Thanks,
Devon Johnson

Inventor 2020
0 Likes
Message 5 of 6

DesignStainless
Explorer
Explorer

Thanks JelteDeJong, Unfortunately I am having the same issue as devonjohnson. I'm clueless when it comes to coding but may I suggest a possible solution.

 

When writing the values for any parts with model states, use Curtis' method in link below.

 

CYCLE THRU MODEL STATES OF PART AND UPDATE CUSTOM PROPERTIES - Autodesk Community  

 

Despite my best efforts I cannot figure it out.

 

Regards, Kris

 

0 Likes
Message 6 of 6

rob
Advocate
Advocate

I'm having similar issues. 

 

I have two versions of an assembly, one which has components with no model states (i.e. 'primary' only), and one for which I've copied in one of the components which also has a 'test1' model state.

 

The code runs fine on the assembly where the components have only the primary model states.

 

For the mixed assembly, the code considers only the components that have only primary model state...it 'skips' the components which have the 'test1' model state.

 

I am just recording the area properties of specifically named surface features in the Custom iProperties for each occurrence, then summing like iProperties from the different occurrences.  The iProperties of the occurrences with model states are blank.

IV Pro 2020.2
0 Likes