How to write a simple "equals" between Model States

How to write a simple "equals" between Model States

chris
Advisor Advisor
588 Views
8 Replies
Message 1 of 9

How to write a simple "equals" between Model States

chris
Advisor
Advisor

I have a part where I have a number fo parameters, and between model states I want certain parameters to always equal whatever the "Primary Model State" parameter equals.

 

Something like this: (below is not actual code, just writing out-loud)

 

(Model State "Second"). Parameter("Length") = (Model State "Primary"). Parameter("Length')

(Model State "Third"). Parameter("Length") = (Model State "Primary"). Parameter("Length')

(Model State "Fourth"). Parameter("Length") = (Model State "Primary"). Parameter("Length')

0 Likes
Accepted solutions (1)
589 Views
8 Replies
Replies (8)
Message 2 of 9

Michael.Navara
Advisor
Advisor

I have limited experience with model states but object ModelStateTable Object. can help you. In this table is described changes of parameters in different model states.

Simple code how to access this table and print table content to iLogic log window

Dim part As PartDocument = ThisDoc.Document
Dim table As ModelStateTable = part.ComponentDefinition.ModelStates.ModelStateTable
Dim rowData As New List(Of String)

For Each column As ModelStateTableColumn In table.TableColumns
    rowData.Add(column.Heading)
Next
Logger.Debug(String.Join(";", rowData))

For Each row As ModelStateTableRow In table.TableRows
    rowData.Clear()
    For Each cell As ModelStateTableCell In row
        rowData.Add(cell.Value)
    Next
    Logger.Debug(String.Join(";", rowData))
Next
0 Likes
Message 3 of 9

chris
Advisor
Advisor

@Michael.Navara Thank you for the replay, I am a little confused as to what this rule is doing. I have a series of kit drawings, all derived from several different kit models, each model with 4 different model states. All of the model states share the base dimensions that change the part size and orientation, and they will always match the "Primary" model state, however, there are a couple dimensions that changes between the states, basically just offsets that help with drawing views, but for the main dimensions, if I change the "Primary" model state form, I want the other states to change to match for their user parameters. I just can't find a way to access model state parameters to make them equal another model state parameter. and for these kits, using the "edit in spreadsheet" for the model states isn't as user-friendly as the iLogic form.

0 Likes
Message 4 of 9

WCrihfield
Mentor
Mentor
Accepted solution

Hi @chris.  I may have something that will work for you, but it has not been tested that much yet.  It also uses the ModelStateTable, because when you need to make things either different or the same between multiple ModelStates, that is pretty much the only way to go.  Otherwise you are left working with one ModelState at a time, and while doing that, you do not have access to values of the same parameter/property in other ModelStates at that time.  This code example can be ran on any type of document.  If ran on a drawing, it will try to get the first 'model' document being referenced by the first view in that drawing.  If none found, it exits the rule.  It utilizes a 'List(Of String)' type variable, which allows you to input multiple parameter names.  This is where you would need to specify the names of all the parameters that you want to be the same across all ModelStates, based on the 'primary' ModelState.  Then it runs a custom Sub routine, then updates the main document.

 

The custom Sub routine first checks that all input data has been provided properly, and that the specified document is either a part or assembly, then makes sure it is working with the 'factory' version, if one is available.  There will not be a 'factory' if there are not 2 or more ModelStates present in it, which it also checks right after that.  If fewer, it exits the routine.  The 'primary' ModelState is always the first one in the ModelStates collection, so it uses that fact to get its name, for reference later (for localization related issues).  Then it gets the table.  Then it gets a reference to the row for the 'primary' ModelState, for reference later.  Since I have not done enough studies to know if the 'primary' ModelState will always be the first row within the ModelStateTable.TableRows collection, I do not assume that, and get it by its name, to be safe.   Then it starts iterating the provided parameter names.  Then it tries to find the column for that specific parameter.  If column is found, it then gets the cell within that row for the primary ModelState for the parameter, using the parameter's column as cross reference for cell location.  Then starts iterating rows.  If the row is the one for primary ModelState, then skip to next row.  Get cell in that row at the parameter column intersection, then set its value using the value from the primary ModelState row's cell...essentially copying the value from the primary ModelState to that non-primary ModelState.  Then it does another update.  I believe a document update may be needed both before and after making parameter type changes to documents which have multiple ModelStates, based on online help documentation describing a situation like that.

 

Below is the code example.

Sub Main
	Dim oDoc As Document = ThisDoc.FactoryDocument 'Nothing if DrawingDocument
	If oDoc Is Nothing Then oDoc = ThisDoc.ModelDocument 'if was DrawingDocument get model
	If oDoc Is Nothing Then Return 'if drawing had no 'model' referenced in it yet
	'define which parameters you want to be the same accross all ModelStates
	Dim oParamNames As New List(Of String)
	oParamNames.Add("Length")
	EnsureParamsSameInAllModelStates(oDoc, oParamNames)
	oDoc.Update2(True)
End Sub

Sub EnsureParamsSameInAllModelStates(oDoc As Document, oParamNames As List(Of String))
	If oDoc Is Nothing Then Return
	If (Not TypeOf oDoc Is AssemblyDocument) AndAlso (Not TypeOf oDoc Is PartDocument) Then Return
	If oParamNames Is Nothing OrElse oParamNames.Count = 0 Then Return
	oDoc.Update2(True) 'may, or may not be needed, but recommended
	If oDoc.ComponentDefinition.IsModelStateMember Then
		oDoc = oDoc.ComponentDefinition.FactoryDocument
	End If
	Dim oMSs As ModelStates = oDoc.ComponentDefinition.ModelStates
	If oMSs.Count < 2 Then Return 'zero or only 1 ModelState, so nothing to do
	Dim sPrimaryMSName As String = oMSs.Item(1).Name
	'Dim sActiveMSName As String = oDoc.ModelStateName
	Dim oMSTable As ModelStateTable = oMSs.ModelStateTable
	Dim oPrimaryMSRow As ModelStateTableRow = oMSTable.TableRows.Item(sPrimaryMSName)
	For Each sParamName As String In oParamNames
		Dim oThisParamCol As ModelStateTableColumn = Nothing
		For Each oCol As ModelStateTableColumn In oMSTable.TableColumns
			If oCol.DisplayHeading = sParamName Then
				oThisParamCol = oCol
				Exit For
			End If
		Next oCol
		If oThisParamCol Is Nothing Then Continue For
		Dim oPrimaryParamCell As ModelStateTableCell = oPrimaryMSRow.Item(oThisParamCol)
		For Each oRow As ModelStateTableRow In oMSTable.TableRows
			If oRow Is oPrimaryMSRow Then Continue For
			Dim oThisParamCell As ModelStateTableCell = oRow.Item(oThisParamCol)
			Try : oThisParamCell.Value = oPrimaryParamCell.Value : Catch : End Try
		Next oRow
	Next sParamName
	oDoc.Update2(True)
End Sub

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

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 9

Frederick_Law
Mentor
Mentor

Set MemberEditScope to Factory/AllMember before changing parameter.

https://help.autodesk.com/view/INVNTOR/2023/ENU/?guid=GUID-BAFCA92B-9EBE-4BEE-AB1D-E09E2A4158C5

0 Likes
Message 6 of 9

chris
Advisor
Advisor

@WCrihfield Thank you, I'm going to play with this after lunch. I don't know why Autodesk doesn't have something in vanilla iLogic to allow for this. I don't know vb or the API, so if there's not a snippet I'm always asking for help. we need something simple like when you're in an assembly and you want to control the parameters of parts from the assembly, but we need that same functionality in a part across model states.

0 Likes
Message 7 of 9

chris
Advisor
Advisor

@WCrihfield This is working great! Thank you so much

0 Likes
Message 8 of 9

chris
Advisor
Advisor

@WCrihfield, could you modify this code to incorporate code from something else? Your code works great, the only drawback is if I have a part with a lot of "user-parameters" then there's a lot of typing, that I could get wrong.

 

@Michael.Navara created a piece of code on a separate post that allows me to easily copy out just the "user-parameter" names, I was wondering if there would be a way to "merge" the two so that when I run your code to make all parameters across all Model states equal the Primary state, that it would also pull the user-defined parameters and add them into your code in the "oParamNames.Add () portion?

 

Here's the code Michael gave for the copy out:

 

Dim part As PartDocument = ThisDoc.Document
Dim userParams = part.ComponentDefinition.Parameters.UserParameters
Dim paramNames As New List(Of String)
For Each param As Parameter In userParams
    paramNames.Add(param.Name)
Next

Dim paramNamesAsLines As String = String.Join(vbCrLf, paramNames)
Logger.Debug("ParamNames{0}{1}", vbCrLf, paramNamesAsLines)

If MsgBox("Copy to clipboard?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
    System.Windows.Forms.Clipboard.SetText(paramNamesAsLines)
End If
0 Likes
Message 9 of 9

Michael.Navara
Advisor
Advisor

For obtaining user param names you can use function like this.

Function GetParamNames(oDoc As Document)
    dim userParams as UserParameters

    If oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject then
        Dim asm as AssemblyDocument = odoc
        userParams = asm.ComponentDefinition.Parameters.UserParameters
    End If  

    If oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject then
        Dim prt as PartDocument = odoc
        userParams = prt.ComponentDefinition.Parameters.UserParameters
    End If
    If userParams Is Nothing Then Return new List(Of string)
            
    Dim paramNames As New List(Of String)
    For Each param As Parameter In userParams
        paramNames.Add(param.Name)
    Next
    Return paramNames

    'Or LINQ single line version
    'Return userParams.OfType(Of Parameter).Select(Function(x) x.Name).ToList()
End Function

 

Usage will be update to

 

Sub Main()
    Dim oDoc As Document = ThisDoc.FactoryDocument 'Nothing if DrawingDocument
    If oDoc Is Nothing Then oDoc = ThisDoc.ModelDocument 'if was DrawingDocument get model
    If oDoc Is Nothing Then Return 'if drawing had no 'model' referenced in it yet
    'define which parameters you want to be the same accross all ModelStates
    Dim oParamNames As List(Of String) = GetParamNames(oDoc)
    'oParamNames.Add("Length")
    EnsureParamsSameInAllModelStates(oDoc, oParamNames)
    oDoc.Update2(True)
End Sub