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: 

Changing Model States of Parts in an Assembly

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
Jack_DuttonTM2JK
457 Views, 7 Replies

Changing Model States of Parts in an Assembly

Hello,

 

I'm working on creating an iLogic rule designed to change the model states of parts within an assembly depending on a binary choice at the beginning. I think I have most of it down, but I am running into the following error, and google has not been able to help me out as the error is a vague one.  

Error on line 29 in rule: Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))

 

What's also strange, is is I say false/off for the prompt at the start, Line 36 will sometimes give the same error, but sometimes say "Class not specified." Can't replicate exactly when it says it. Just sometimes. 

 

Below is my code, edited slightly to remove most comments:

iLogicVb.UpdateWhenDone = True 

Dim IsVisible As Boolean = InputRadioBox("Turn all Model States On/Off", "On", "Off", False, "Model State Toggle") 

Dim oAssyDoc As AssemblyDocument 
oAssyDoc = ThisApplication.ActiveDocument

Dim oRefDocs As DocumentsEnumerator 
oRefDocs = oAssyDoc.AllReferencedDocuments

Dim oRefDoc As Document 

For Each oRefDoc In oRefDocs
	If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then 
		oModelStates = oRefDoc.ComponentDefinition.ModelStates
		
		If IsVisible = True
			Dim oModelState As ModelState
			oModelState = oModelStates.Item("ModelState2").Activate '<-- Line 29

		End If
		
		If IsVisible = False
			Dim oModelState As ModelState
			oModelState = oModelStates.Item("[Primary]").Activate '<--Line 36
				
		End If
	End If
Next	

 Any help would be much appreciated!

7 REPLIES 7
Message 2 of 8

Not all files has ModelState?

Message 3 of 8

I created a dummy assembly with multiple sub assemblies and parts. All sub assemblies consist of just one part copied over and over again. So really it's just 25 instances of 1 part.
That part has the [Primary] Model State and the ModelState2 model state. The assemblies have the [Primary] Model state and a few others not called ModelState2.
Message 4 of 8

Add: Logger.Info(oRefDoc.FullFileName) after For to see which file is the problem.

You can see it in iLogic Log window.

Need to set log level to Info.

 

Maybe it cannot activate ModelState that is activated.

Check ActiveModel State first:

https://help.autodesk.com/view/INVNTOR/2024/ENU/?guid=ModelStates_ActiveModelState

Message 5 of 8

Hi @Jack_DuttonTM2JK , there were a few things I noticed.

 

  1. The name might need to be Model State2, with a space, if you allowed Inventor to name it, but that might not be an issue if you set the name, sans space.
  2. the line below is attempting to get the model state in a variable and activate it all at once
    • So it's sort of a mix of the noun/verb
oModelState = oModelStates.Item("ModelState2").Activate '<-- Line 29

So we could do this with 2 lines, here we get the model state (noun)  on the first line and then activate it (verb) on the second line, to get this to work:

		oModelState = oModelStates.Item("ModelState2")
		oModelState.Activate

But having said that, since we're not really doing anything with the variable( the noun) , we don't really need it. We can just go straight to the verb and issue the action directly;

oModelStates.Item("ModelState2").Activate

 

3. With all of that in mind, the larger issue is that we need to access the factory document and get the model states collection from it, but the assembly is referencing a member document.

 

Frederick_Law's suggestion to peek at the logger was close, but if you were to look at the fullfilename of the part that is oRefDoc it would be something like this:

C:\Temp\Part1.ipt

but the fulldocumentname of oRefDoc would be something like this:

      C:\Temp\Part1.ipt<Model State2>

 

So basically if we're working with a referenced document with model states we need to track up from it and get its factory document.

 

You can think of Model States like iParts in this sense that each member is it's own document and belongs to a parent/factory document. It's just that for model states, the member documents are "virtual" and don't live on disk, so we as users don't really know they exist, until we start doing this sort of task.

 

In any case, give this a try and I think it will work for you.

 

iLogicVb.UpdateWhenDone = True

Dim IsVisible As Boolean = InputRadioBox("Turn all Model States On/Off", "On", "Off", False, "Model State Toggle")

Dim oAssyDoc As AssemblyDocument
oAssyDoc = ThisDoc.Document

Dim oRefDocs As DocumentsEnumerator
oRefDocs = oAssyDoc.AllReferencedDocuments

Dim oRefDoc As Document

For Each oRefDoc In oRefDocs
	If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		Logger.Info(oRefDoc.FullFileName)
Logger.Info(oRefDoc.FullDocumentName)
Dim oDoc As PartDocument = oRefDoc.ComponentDefinition.FactoryDocument
Dim oModelStates As ModelStates = oDoc.ComponentDefinition.ModelStates If IsVisible = True oModelStates.Item("ModelState2").Activate ElseIf IsVisible = False oModelStates.Item("[Primary]").Activate End If End If Next

 

Message 6 of 8

Hi @Curtis_Waguespack and @Frederick_Law,

 

Thank you both for your help! 

 

I implemented the changes Curtis proposed and no Error! However the code isn't doings what it's supposed to. Checking the log it's able to find the parts in the assembly, but it's not changing the models states. 

I ran some tests on just a part file to make sure it would work, and it does. Just using a smaller version of the code above: 

 

Dim IsVisible As Boolean = InputRadioBox("Turn all Model States On/Off", "On", "Off", False, "iLogic")

Dim oDoc As PartDocument = ThisDoc.Document
Dim oModelStates As ModelStates = oDoc.ComponentDefinition.ModelStates

	If IsVisible = True
		oModelStates.Item("ModelState2").Activate
ElseIf IsVisible = False oModelStates.Item("[Primary]").Activate End If   

I put some MsgBox("test") commands after the If statements on IsVisible, and it reaches them. So Maybe the Activate command just doesn't work from the assembly level? Is this something you'd have to "traverse" the assembly for? I've seen that in some other commands but haven't used it before. 

 

Again, thanks for the help!

Message 7 of 8

@Jack_DuttonTM2JK, have a look at these examples.

The challenge to set a MS in all levels comes from the following:

  • we can't push MS changes down more then one level in an assembly
  • we can't just open the document and set the MS without updating the MS in the assembly it is used

So the 3rd example attempts to chain all this together, but I've not tested it well to see where it might run into issues. I left a lot of logger lines in it for you to try and help debug should you run into issues testing this, but in production it would be better to comment those out since writing lots of log lines can slow things down.

 

Hope this helps,

Curtis

 

1) Activate MS at document level

Dim IsVisible As Boolean = InputRadioBox("Turn all Model States On/Off", "On", "Off", False, "iLogic")

Dim oDoc As Document = ThisDoc.Document.ComponentDefinition.FactoryDocument
Dim oModelStates As ModelStates = oDoc.ComponentDefinition.ModelStates

If IsVisible = True
	oModelStates.Item("ModelState2").Activate

ElseIf IsVisible = False
	oModelStates.Item("[Primary]").Activate
End If   

 

2) Activate MS at first assembly level 

( probably no reason to use this version, but it does provide a cleaner example of what is needed to work with MSs from the assembly)

iLogicVb.UpdateWhenDone = True

Dim IsVisible As Boolean = InputRadioBox("Turn all Model States On/Off", "On", "Off", False, "Model State Toggle")

Dim oAssyDoc As AssemblyDocument
oAssyDoc = ThisDoc.Document

Dim oDoc As PartDocument
For Each oOcc As ComponentOccurrence In oAssyDoc.ComponentDefinition.Occurrences.AllLeafOccurrences

	If oOcc.Definition.Document.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		oDoc = oOcc.Definition.Document
		oDoc.Update2(False)

		If IsVisible = True
			oOcc.ActiveModelState = "ModelState2"
		ElseIf IsVisible = False
			oOcc.ActiveModelState = "[Primary]"
		End If
	End If
Next

 

3) Activate MS at all levels 
(Since we can't push MS changes down more then one level in an assembly, we need open the document and set the MS, and then set the MS in the assembly it is used in)

Sub Main

	Dim IsVisible As Boolean = InputRadioBox("Select", "MS2", "Primary", False, "Model State Toggle")

	Dim oDoc As AssemblyDocument = ThisDoc.Document

	'activate ModelState in the top level
	If IsVisible = True
		ThisDoc.ActiveModelState = "ModelState2"
	ElseIf IsVisible = False
		ThisDoc.ActiveModelState = "[Primary]"
	End If

	oMSName = ThisDoc.ActiveModelState

	Call TraverseAssembly(oDoc.ComponentDefinition.Occurrences, oMSName)

	InventorVb.DocumentUpdate()
End Sub

Dim ProcesssedDocumentsList As New ArrayList

Sub TraverseAssembly(Occurrences As ComponentOccurrences, oMSName As String)
	Dim oDoc As AssemblyDocument

	Dim oOcc As ComponentOccurrence
	For Each oOcc In Occurrences


		If oOcc.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
			Call TraverseAssembly(oOcc.SubOccurrences, oMSName)
		End If

		'get the parent, if it exists, open it and activate the model states in it
		If oOcc.ParentOccurrence IsNot Nothing Then
			Logger.Info("oOcc: " & oOcc.Name)
			Logger.Info("parent: " & oOcc.ParentOccurrence.Name)
			Call OpenParent(oOcc.ParentOccurrence, oMSName)
			ProcesssedDocumentsList.remove(oParentName = oOcc.ParentOccurrence.Definition.Document.fullfilename)
		End If

		InventorVb.DocumentUpdate() 'this update is important to keep the assembly synced
		Logger.Info("      oOcc: " & oOcc.Name)
		Logger.Info("Current MS: " & oOcc.ActiveModelState.ToString)
		Try
			oOcc.ActiveModelState = oMSName
		Catch
			Logger.Info("!!!!!      Could not activate : " & oMSName & " in " & oOcc.Name)
		End Try
	Next
End Sub

Sub OpenParent(oParent As ComponentOccurrence, oMSName As String)

	oParentDoc = oParent.Definition.Document
	oParentDoc.Update2(False)
	oParentName = oParentDoc.fullfilename
	Logger.Info("oParentName: " & oParentName)

	'if this doc has been proccessed already, skip it
	If ProcesssedDocumentsList.contains(oParentName) Then Exit Sub

	oDoc = ThisApplication.Documents.Open(oParentName, False)
	Logger.Info("      Opened: " & oDoc.fullfilename)

	ProcesssedDocumentsList.add(oDoc.fullfilename)

	oFactoryDoc = ThisDoc.Document.ComponentDefinition.FactoryDocument
	Try
		oFactoryDoc.ComponentDefinition.ModelStates(oMSName).activate
	Catch
		Logger.Info("!!!!!!!!!!!!!!!!!!!! Could not activate : " & oMSName & " in " & oParentName)
	End Try

	For Each iOcc In oDoc.ComponentDefinition.Occurrences
		Logger.Info("iOcc: " & iOcc.Name)
		iOcc.ActiveModelState = oMSName
	Next
	oDoc.Close
	Logger.Info("        Closed: " & oDoc.fullfilename)
End Sub

 

Message 8 of 8

WOOOW! Curtis you are a GENIUS! It took me some time to go line by line and understand everything, but it works perfectly! I made a few personal adjustments right at the top to not change the parent document model states. So I just commented out the:

	If IsVisible = True
		ThisDoc.ActiveModelState = "Cad_Aids"
	ElseIf IsVisible = False
		ThisDoc.ActiveModelState = "[Primary]"
	End If
	oMSName = ThisDoc.ActiveModelState

 And replaced it with:

	If IsVisible = True
		oMSName = "ModelStates2"
	ElseIf IsVisible = False
		oMSName = "[Primary]"
	End If

Mine is less future proof with the hard callouts, but it works out, haha. 

 

But honestly I first tested it but just copy pasting you exact code and it worked, so again thank you very much sir! 

 

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

Post to forums  

Autodesk Design & Make Report