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: 

iLogic Code to change between Model State on an Assembly

27 REPLIES 27
SOLVED
Reply
Message 1 of 28
frahaman7SKBG
5638 Views, 27 Replies

iLogic Code to change between Model State on an Assembly

Hi guys, 

 

I need some help with iLogic. I have an assembly where 8 of the 10 parts are driven by Multi-Body Model State. The source Multi-Body part has multiple Model States with various sizes. I would like to have a form in the Assembly where the user enters the Model state that they want their assembly to corresponding to.

 

From my basic understanding of iLogic, we want the iLogic rule to open all the  8 individual components and change the Multi State to what the user entered in the form. With the help from the post below, I was able to run external rules where the code goes to the individual components and changes the model state. The difficulty I'm having is where I want to incorporate the Form function with user input for the Model State. Currently I'm opening the source code and manually changing the Multi-State name, I would like to change this so the users don't mess around the source code and just uses the Form to change between the Model States. 

 

 

https://forums.autodesk.com/t5/inventor-ilogic-api-vba-forum/change-drive-part-model-stage-using-ilo... 

 

27 REPLIES 27
Message 2 of 28
WCrihfield
in reply to: frahaman7SKBG

This sounds fairly simple when you say it, but I'm thinking it will be more complicated than it sounds.  In order to use an iLogic Form in the main assembly that will allow you to change the ModelState of all those components, you would likely have to create a multi-value, text type user parameter within your main assembly for each of those components, that contains the names of each available ModelState within that component.  Then you will need to create the Form.  Then you will need to create a rule that is triggered by those specific user parameters changing in that main assembly.  Then this rule will need to be able to identify which parameter is for which component, so that when you loop through the components, it will know which parameter to get the ModelState name from to assign to the component.  This is just a game plan for the project.  One additional tool you may or may not need to help in this task, is a rule that will loop through those components first, get their list of available ModelState names, and write them to the multi-value parameters in your main assembly.  Then if you continue to develop any of those components and add or subtract from those ModelStates, you would need to run this rule again to update the parameters multi-value lists, or update them manually.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 3 of 28

Hi @frahaman7SKBG 

It sounds like you're looking for something like this? 🙂

You can create a multivalue parameter, in my case named ModelStates and have a rule that tries to update all the occurrences modelstates in the assembly to that parameters value.

Sub Main
Dim oAsm As AssemblyDocument = ThisDoc.Document
Dim oDef As AssemblyComponentDefinition = oAsm.ComponentDefinition
For Each oOcc As ComponentOccurrence In oDef.Occurrences
	Try
		ChangeState(oOcc, ModelStates)
	Catch
	End Try
Next
End Sub
Sub ChangeState(occ As ComponentOccurrence, stateName As String)
	occ.ActiveModelState = stateName
End Sub

 

Message 4 of 28
JhoelForshav
in reply to: JhoelForshav

I forgot to add the screencast

Message 5 of 28

Thanks @However, I was able to come up with a solution that seem to be doing the task I wanted.

 

I first use one rule to take user input to capture the new Model State and place it as a custom iProperty and then use another rule to push this custom iProperty that has a new Model State name to all the sub-assemblies and parts. I have added a rule to all the sub-assemblies and parts to change Model State to what the custom iProperty has. And then I run another rule in my man assembly that runs this rule that is on each individual part. Below are snippets of all the rules. Let me know if there is a faster/better way of doing this.

Let me know if my explanation makes sense, can do a screencast to show how it works. 

 

Step 1: 

'Promt the user for the value of a variable
modelstate = InputBox("Please Enter the Model Sate Here", "Custom Property Input Box", "Eg. 21017-xxx")

'assign the value of that variable to a custom property
iProperties.Value("Custom", "Model_State:") = modelstate

Step 2: 

Sub Main
'Gets the Active Document
oDoc = ThisDoc.Document

'Saves this document
oDoc.Save

'Checks if the active document is an assembly
If oDoc.DocumentType = kAssemblyDocumentObject
	'Gets the assembly occurrences
	Dim oOccs As ComponentOccurrences
	oOccs = oDoc.ComponentDefinition.Occurrences
	'Call the subprocedure to traverse the assembly
	Call TraverseAssembly(oOccs)
End If

End Sub

'***************
Public Sub TraverseAssembly(oOccs As ComponentOccurrences)
 'Integer to traverse the assembly occurrences
 Dim i As Integer
 
 'For i=1 To oOccs.Count
  Dim oOcc As ComponentOccurrence
For Each oOcc In oOccs
  'oOcc = oOccs.Item(i)  
 	If oOcc.Suppressed = False
   
		'Occurrence Name (Display Name)
		oOccName = oOcc.Name
		
		'Gets the first three leters of the Occurrence Name (e.g. "STK")
		oOccPrefix = Left(oOccName, 3)
		
		If oOccPrefix <> "STK"
		
			Try
'				
				iProperties.Value(oOccName, "Custom", "Model_State:") = iProperties.Value("Custom", "Model_State:")
			
				
			Catch
				'It won't be able to change Read-Only parts (e.g. Content Center)
				'MessageBox.Show("This is a content center file: " & oOcc.Name, "Title")
			End Try
		End If

		If oOcc.DefinitionDocumentType = kAssemblyDocumentObject
			Call TraverseAssembly(oOcc.SubOccurrences)
		End If
	End If
Next
End Sub

 

Step 3: 

Sub Main
auto = iLogicVb.Automation

' Set Rule name
Dim ruleName As String
ruleName = "Update_Model_State"

' Get the active assembly. 
Dim oAsmDoc As AssemblyDocument 
oAsmDoc = ThisApplication.ActiveDocument 

' Get all of the referenced documents. 
Dim oRefDocs As DocumentsEnumerator 
oRefDocs = oAsmDoc.AllReferencedDocuments 

' Iterate through the list of documents. 
Dim oRefDoc As Document 

For Each oRefDoc In oRefDocs
	Dim rule As Object
	rule = auto.GetRule(oRefDoc, ruleName)
	If (rule Is Nothing) Then
'	Call MsgBox("No rule named " & ruleName & " was found in the document.")
	Else
'	MessageBox.Show(rule.Name, oRefDoc.DisplayName)
	
	Dim i As Integer
	i = auto.RunRuleDirect(rule)
	
	End If

Next 
End Sub

Here is the rule that is in the individual parts: 

 

Dim doc As PartDocument = ThisDoc.Document
Dim comp As DerivedPartComponent = doc.ComponentDefinition.ReferenceComponents.DerivedPartComponents.Item(1)
Dim derivedDef = comp.Definition
Logger.Info("current model state = {0}", derivedDef.ActiveModelState)
Dim stateWanted = iProperties.Value("Custom", "Model_State:")
If (derivedDef.ActiveModelState <> stateWanted) Then
	derivedDef.ActiveModelState = stateWanted
	comp.Definition = derivedDef ' apply the modified definition back to the DerivedPartComponent
End If

 

 

Message 6 of 28
WCrihfield
in reply to: frahaman7SKBG

Hi @frahaman7SKBG.  Most of your code looks OK at first glance, but there was one point in 'Step 2' code that I saw that I believe will need to be changed.  You are using a Sub routine in that rule that accepts a ComponentOccurrences object as its input variable.  You are using this properly the first time, within your main Sub of that rule, but within that 'TraverseAssembly' Sub itself, where it calls itself again, you are supplying it with a ComponentOccurrencesEnumerator object, which I don't think will work.  You should get the ComponentOccurrences from that assembly type component's definition, and use that as input for that Sub routine, similarly to how you did in the main Sub part of that rule instead.  Does that make sense to you?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 28
frahaman7SKBG
in reply to: WCrihfield

Hi @WCrihfield , Thanks for your response. 

 

I am not an expert in iLogic in any capacity. Most of my codes are taken as snippets from various forums and modified slightly to suit my needs. I think I understand what you are saying, but I don't have the in-depth knowledge on how to put it in code format. Would you be able to provide me with a snippet that I can use? Thank you for all your wonderful help and suggestion. 

Message 8 of 28
WCrihfield
in reply to: frahaman7SKBG

Sure.  This is just a slight update to the code you posted in your 'Step 2' above.

Mainly I just changed this line:

Call TraverseAssembly(oOcc.SubOccurrences)

to this:

TraverseAssembly(oOcc.Definition.Occurrences)

Because oOcc.SubOccurrences returns a ComponentOccurrencesEnumerator object, and the  oOcc.Definition.Occurrences returns a ComponentOccurrences object, which matches the Type of the input variable specified in the definition line of the TraverseAssembly Sub routine.  Also you don't really need to include the term 'Call' in front of those lines in iLogic.  That is more for use in a VBA macro.

Here is the whole thing again, just to be clear.

Sub Main
	'Gets the 'local' document (the one this rule is saved within)
	'or the document that was 'Active' when the rule started
	oDoc = ThisDoc.Document
	'Saves this document
	oDoc.Save
	'Checks if the active document is an assembly
	If oDoc.DocumentType = kAssemblyDocumentObject
		'Gets the assembly occurrences
		Dim oOccs As ComponentOccurrences = oDoc.ComponentDefinition.Occurrences
		'Call the subprocedure to traverse the assembly
		TraverseAssembly(oOccs)
	End If
End Sub

'***************
Public Sub TraverseAssembly(oOccs As ComponentOccurrences)
	Dim oOcc As ComponentOccurrence
	For Each oOcc In oOccs
		If oOcc.Suppressed = False Then
			'Occurrence Name (Display Name)
			oOccName = oOcc.Name
			'Gets the first three leters of the Occurrence Name (e.g. "STK")
			oOccPrefix = Left(oOccName, 3)
			If oOccPrefix <> "STK" Then
				Try	
					iProperties.Value(oOccName, "Custom", "Model_State:") = iProperties.Value("Custom", "Model_State:")
				Catch
					'It won't be able to change Read-Only parts (e.g. Content Center)
					'MessageBox.Show("This is a content center file: " & oOcc.Name, "Title")
				End Try
			End If
			If oOcc.DefinitionDocumentType = kAssemblyDocumentObject
				TraverseAssembly(oOcc.Definition.Occurrences)
			End If
		End If
	Next
End Sub

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 9 of 28
frahaman7SKBG
in reply to: WCrihfield

Thank you @WCrihfield
Message 10 of 28
esimers
in reply to: frahaman7SKBG

Ok, so I think I need to figure this out for a project.

I have a multibody part that drives a Main Assembly, I need to be able to switch model states on each part via ONE main switch in the Main Assembly.    But I'm not sure where to put each part of these codes?  IE what code needs to be in the multibody part? What needs to be in the Main Assembly?  What needs to be in each part?

Thanks in advance for any insight and assistance.

Message 11 of 28
GosponZ
in reply to: JhoelForshav

HI Jhoel Forshav,

that works great but have some question about. I do have 3 MS in part level and 3 in assembly. They named same.

When i switching MS from assembly it is working just as supposed. When using you rule there is no error but it changed on assembly level but not on part level. It is not in sinc. Could you help i would like to change as you present in video which is working awsome.

 

Thank you

Message 12 of 28
WCrihfield
in reply to: GosponZ

Hi @GosponZ.  It sounds like you are wanting to simulate the 'Link ModelStates' tool, but from an iLogic rule, is that correct?  If so, then the only thing you would likely need to add to the routine is to loop through each of the main assembly's ModelStates, activate it, then loop the components, trying to set them to a ModelState with the same name as the currently active assembly ModelState.  I posted an example of this process last year at the following link:

https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/how-to-link-model-states-in-an-assem... 

However, I would probably enclose that one line that is trying to set the ModelState of components within a Try...Catch block, to avoid the potential errors that would occur when the component does not have a ModelState available to it with the same name.

Try : oOcc.ActiveModelState = oMS.Name : Catch : End Try

...and I would likely change the oADoc.Update to oADoc.Update2(True).

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 13 of 28
GosponZ
in reply to: WCrihfield

Thank you for fast answer. I tried all possible ways i cold think off but no success. So again 3  text parameters. 3 ms part level and 3 ms in assembly. Would like to change thru form like in above example.

Message 14 of 28
GosponZ
in reply to: GosponZ

Anybody try?

Message 15 of 28
t_fransman
in reply to: WCrihfield

IS there any way you can make this iterate through sub assemblies and any opart driven by a muitl solid so the shildren change when i change the model state in the assembly so that the children from the multibody change to the same. CAn't find a way to edit derived part and make all of the model states match so i can use the top level assembly in mutiple states. Basically the children do not change when i change the model state of the assembly. 

Message 16 of 28
WCrihfield
in reply to: t_fransman

Hi @t_fransman.  Unfortunately I do not have time to tackle this one today, but hopefully I can get back here to work on this tomorrow, if I don't forget, or get swamped with other stuff.  This can certainly be a pretty complex task to automate properly.  And controlling that many levels of ModelStates in an assembly is not really something that I have ever needed to deal with where I work, especially where derived parts are involved (or skeleton modeling in an assembly).

 

I have dealt with first level components before, as you can see in the article I had a link to above, but perpetuating a top level ModelState change down to lower levels is more complicated, and would require the use of a 'recursive' Sub routine.  One important factor in this type of routine is how you step down into each lower level.  We can either use ComponentOccurrence.SubOccurrences property, or we can use ComponentOccurrence.Definition.Occurrences property.  Which one you use can make a big difference, because it changes 'context'.  Using SubOccurrences tends to keep the context 'as seen by the main assembly', while the other is more strict, only making changes within the definitions of those other referenced documents.  One thing that may need to be included in a process like this is saving these ModelState status changes at each level of the assembly, within that parent assembly's active ModelState.  But similar to dealing with view representations, this type of thing is best set up manually, starting with the lowest level parts, then lowest level sub assemblies, then stepping up the assembly structure until you get to the top level.  Trying to do processes like this starting from the top level, then down through multiple levels is very challenging to get to work out correctly.

 

In the example codes that @frahaman7SKBG posted in Message 5, within the fourth code window, is a similar process that would have to be dealt with to change the ModelState of a derived part.  But getting that change to show at the top level of an assembly that this component may be in a lower level of is another challenge.  And I do not believe that whatever ModelState was active in the host part will record which ModelState you set the 'derived in' part to, so controlling that at the assembly level is going to be very challenging also, if possible.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 17 of 28
t_fransman
in reply to: WCrihfield

THANKS BECAUSE THE OTHER CODE SEE MY HARDWARE AND THE FACT I HAVE A COUPLE BASIC WELDMENTS PROBABLY AND CRASHES MY SESSION EVERY TIME. 

 

Message 18 of 28
t_fransman
in reply to: frahaman7SKBG

i just can't believe that this is not a fundamental default behavior. Lol

Message 19 of 28
t_fransman
in reply to: frahaman7SKBG

Another issue i am having (that may be easier to fix) is if i add the skeleton to the spreadsheet and make all the matching lines so it changes when a model state is selected at the top level it works but my rules to change number of of holes in the skeleton does not update until i open the skeleton.  I've tried many event triggers at the skeleton level  to no effect. 

Message 20 of 28
WCrihfield
in reply to: t_fransman

Hi @t_fransman.  I finally found my way back here.  I just typed/assembled some code that you can put into a single external iLogic rule for hopefully handling a large part of this task, but I did not leave much in the way of comments or feedback messages in there, because I was in a hurry.  The main two things this code will attempt to do is the following:

  • Get the name of the active ModelState of the main assembly, then recursively iterate through every assembly component, at every level, and attempt to set each of them to that same ModelState, but only if a ModelState by that same name already exists within the file that they are referencing.  If any of them are suppressed, or virtual, similar oddity, it will skip over them.  This means that if you have a component suppressed that represents a sub assembly, it will not do anything with that component, or any if its sub components.  We can not do much with a component that is suppressed.
  • Get the collection of all referenced documents, iterate through them, if they are a part, check if they have another part derived into them, if so, try to change the ModelState of the 'source' part that is being derived into it.

I am not experienced with 'skeleton' modeling in an assembly, so if that is what you are doing, I may not be able to help much with that aspect of the project.

The code I have is in the attached text file.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

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

Post to forums  

Autodesk Design & Make Report