Using iLogic to write a variable value to a parameter with a given name that exists in multiple parts

Using iLogic to write a variable value to a parameter with a given name that exists in multiple parts

fridtjofZM5ME
Collaborator Collaborator
2,938 Views
5 Replies
Message 1 of 6

Using iLogic to write a variable value to a parameter with a given name that exists in multiple parts

fridtjofZM5ME
Collaborator
Collaborator

Learning iLogic on my own through google and this forum as I go along, I encountered a problem I couldn't figure out on my own:

 

You have an iLogic rule in the top level assembly, where you also have a sub-assembly containing 25 unique parts, each part featuring a parameter named "Bird".

 

within the iLogic you state the following:

Dim sBird As String = "Chicken"

next you want to write the value of the variable "sBird" to the parameter named  "Bird" in all the places "Bird" occurs within the sub-assembly. I would guess it goes something like:

For Each [parameter named "Bird"] In Each [partfile] In [sub-assembly]
    Bird = sBird
Exit

but I honestly have no clue, as I haven't found a tangible explanation for how the "For Each"-loop works, how to use it, or what to use it for. At least nothing that I've managed to relate to what I'm trying to acheive here.

 

The intended result is obviously that the parameter named "Bird" in each of the part files now has the value "Chicken" after three lines of code, rather than 25 lines as exemplified below:

 

Parameter("partfile1:1, "Bird") = sBird
Parameter("partfile2:1, "Bird") = sBird
Parameter("partfile3:1, "Bird") = sBird
...
Parameter("partfile25:1, "Bird") = sBird

 

If anyone could tell me how to get this to work, or if the rational way to go about this is something else entirely, I'd be really happy to know.

0 Likes
Accepted solutions (2)
2,939 Views
5 Replies
Replies (5)
Message 2 of 6

WCrihfield
Mentor
Mentor

I think this may work for what you are trying to do.  It just loops through the main assembly's AllReferencedDocuments collection, instead of targeting one specific sub-assembly, but if that's not a problem, it should work just fine.  (You could also possibly loop through AllLeafOccurrences for this purpose.)

Here's the iLogic code:

 

If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
	MsgBox("An Assembly Document must be active for this rule to work. Exiting.",vbOKOnly+vbCritical, "WRONG DOCUMENT TYPE")
	Exit Sub
End If
Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
Dim oBird As String = "Chicken"
For Each oRefDoc As Document In oADoc.AllReferencedDocuments
	'avoid working with it if it's not a Part
	If oRefDoc.DocumentType <> DocumentTypeEnum.kPartDocumentObject Then Continue For
	Dim oPDoc As PartDocument = oRefDoc
	'check for that parameter
	Dim oExists As Boolean = False
	Dim oParam As Inventor.Parameter
	For Each oParam In oPDoc.ComponentDefinition.Parameters
		If oParam.Name = "Bird" Then
			oExists = True
			oParam.Value = oBird
		End If
	Next
	If oExists = False Then
		oAns = MsgBox("The Parameter named 'Bird' was not found in the following part:" & vbCrLf & _
		oPDoc.FullFileName & vbCrLf & _
		"Do you want to create it?", vbYesNo + vbQuestion, "Param Not Found")
		If oAns = vbYes Then
			oParam = oPDoc.ComponentDefinition.Parameters.UserParameters.AddByValue("Bird", oBird, UnitsTypeEnum.kTextUnits)
		End If
	End If
Next

 

If this solved your problem, or answered your question, please click ACCEPT SOLUTION.
Or, if this helped you, please click (LIKE or KUDOS) 👍.

If you want and have time, I would appreciate your Vote(s) for My IDEAS 💡or you can Explore My CONTRIBUTIONS

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 3 of 6

fridtjofZM5ME
Collaborator
Collaborator

Thanks @WCrihfield 

 

So here's my subroutine customized to work in the context of my specific case (string variables, brids and chickens were used in the initial post for illustrative purposes, though they are actually double variables with a nummeric value. I didn't think it mattered logically at the time)

 

 

 

Sub Innfestning()
	
	Dim inAIV As Integer
	Dim inAIH As Integer
	Dim dBAI As Double
	Dim dTAI As Double = 268 mm 
	Dim dSAI As Double = 268 mm
	Dim dTerskelHøyde014 As Double = Parameter("LMV - SK5-014:1", "Hengsleside")
	
	If Terskel = "Kvilldal" Then
			dBAI = 250 mm
	Else If Terskel = "014" Then
			dBAI = dTerskelHøyde014 + 235 mm
	End If 
	
	
	If AntInfV <> 0 Then
		inAIV = AntInfV
	Else
		inAIV = Math.Ceiling((KarmHøyde - dBAI - dTAI) / 530 mm ) + 1
	End If
	
	
	If AntInfH <> 0 Then
		inAIH = AntInfH
	Else
		inAIH = Math.Ceiling((KarmBredde - 2 * dSAI) / 530 mm ) + 1
	End If
	
	Logger.Debug("BAI =" & dBAI)
	Logger.Debug("SAI =" & dSAI)
	Logger.Debug("nAIV =" & inAIV)
	
	Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
	
	For Each oRefDoc As Document In oADoc.AllReferencedDocuments
		
		If oRefDoc.DocumentType <> DocumentTypeEnum.kPartDocumentObject Then Continue For	'skip if not part document
			Dim oPDoc As PartDocument = oRefDoc
			
			Dim oExists As Boolean = False
			Dim oParam As Inventor.Parameter
			
				For Each oParam In oPDoc.ComponentDefinition.Parameters
					If oParam.Name = "nAIV" Then
						oExists = True
						oParam.Value = inAIV 
						Logger.Debug("Para nAIV =" & oParam.Value)
					End If
				Next
				
				For Each oParam In oPDoc.ComponentDefinition.Parameters
					If oParam.Name = "BAI" Then
						oExists = True
						oParam.Value = dBAI
						Logger.Debug("Para BAI =" & oParam.Value)
					End If
				Next
				
				For Each oParam In oPDoc.ComponentDefinition.Parameters
					If oParam.Name = "TAI" Then
						oExists = True
						oParam.Value = dTAI
						Logger.Debug("Para TAI =" & oParam.Value) 
					End If
				Next
				
				For Each oParam In oPDoc.ComponentDefinition.Parameters
					If oParam.Name = "SAI" Then
						oExists = True
						oParam.Value = dSAI
						Logger.Debug("Para SAI =" & oParam.Value)
					End If
				Next
				
				For Each oParam In oPDoc.ComponentDefinition.Parameters
					If oParam.Name = "nAIH" Then
						oExists = True
						oParam.Value = inAIH
						Logger.Debug("Para nAIH =" & oParam.Value)
						
					End If
				Next
	Next
	
	Logger.Debug("BAI =" & dBAI)
	Logger.Debug("SAI =" & dSAI)
	Logger.Debug("nAIV =" & inAIV)
	
	
End Sub 

 

 

This sort of works and sort of does what I intend it to do; it runs without errors and writes a value to the parameters specified. However, the value written to the parameters is ten times the nummeric value of the double variables, which writes to a parameter with the unit "mm", while the value written by the integer variables to unitless parameters stays the same. I really don't understand why this happens, as it doesent appear to matter whether I specify the unit after the value when typecasting the variable or not.

 

Also, the code here seem very cumbersome to write, could this be done by setting an array of parameter names as the condition for oExists = true and then write and array of variables to the corresponding array of parameter names just to get rid of several lines of code?

0 Likes
Message 4 of 6

J-Camper
Advisor
Advisor

So another route would be to build the list like you mentioned and just run everything through a Try/Catch Statement.  Try/Catch, if you don't already know, will process the Try portion until it encounters an error [in this case that would mean the parameter doesn't exist] at which point it stops at the error and runs through the Catch Portion.  If there is no error, then the Catch Portion is ignored.

 

Try this:

Sub Innfestning()
	
	Dim inAIV As Integer
	Dim inAIH As Integer
	Dim dBAI As Double
	Dim dTAI As Double = 268 mm 
	Dim dSAI As Double = 268 mm
	Dim dTerskelHøyde014 As Double = Parameter("LMV - SK5-014:1", "Hengsleside")
	
	If Terskel = "Kvilldal" Then
			dBAI = 250 mm
	Else If Terskel = "014" Then
			dBAI = dTerskelHøyde014 + 235 mm
	End If 
	' dBAI can be nothing because a default is not set
	
	If AntInfV <> 0 Then
		inAIV = AntInfV
	Else
		inAIV = Math.Ceiling((KarmHøyde - dBAI - dTAI) / 530 mm ) + 1
	End If
	
	
	If AntInfH <> 0 Then
		inAIH = AntInfH
	Else
		inAIH = Math.Ceiling((KarmBredde - 2 * dSAI) / 530 mm ) + 1
	End If
	
	Logger.Debug("BAI =" & dBAI)
	Logger.Debug("SAI =" & dSAI)
	Logger.Debug("TAI =" & dTAI)
	Logger.Debug("nAIV =" & inAIV)
	Logger.Debug("nAIH =" & inAIH)
	
	Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
	
	Dim oParamList As NameValueMap = ThisApplication.TransientObjects.CreateNameValueMap
	oParamList.Add("nAIV", inAIV)
	oParamList.Add("BAI", dBAI)
	oParamList.Add("TAI", dTAI)
	oParamList.Add("SAI", dSAI)
	oParamList.Add("nAIH", inAIH)
		
	For Each oRefDoc As Document In oADoc.AllReferencedDocuments
		
		If oRefDoc.DocumentType <> DocumentTypeEnum.kPartDocumentObject Then Continue For	'skip if not part document
		Dim oPDoc As PartDocument = oRefDoc
		Dim oParam As Inventor.Parameter
		For i = 1 To oParamList.Count
			Try
				oParam = oPDoc.ComponentDefinition.Parameters.Item(oParamList.Name(i))
				oParam.Expression = oParamList.Value(oParamList.Name(i)) & oParam.Units
			Catch
				Logger.Debug(oPDoc.DisplayName & "  does not have parameter:  " & oParamList.Name(i))
			End Try
		Next
	Next
End Sub 

 

I couldn't really test the first half of the code because I don't have the Parameters/Variables you are referencing in your If/Then statements.  But if those Debug Logs are reading correctly, then I think this should work.

 

One other thing to note here, I am not looping through each part's Parameters, because you can Index the Item with Parameter name.

 

Let me know if you have any questions, or if this is not working as intended

Message 5 of 6

WCrihfield
Mentor
Mentor
Accepted solution

Yes that whole unfortunate 'database units' thing really disappoints a lot of folks.  We have do deal with it every time we retrieve or write to a parameter using iLogic (among other situations).  To deal with it we usually either include a little math where needed, or use a units conversion subroutine to deal with it.  I attempted to use a Dictionary type collection to store the pairs of parameter names and values you intend to write to them, for use within the lower loop.  I couldn't test it, so let me know how it works for you.  I had to rename the main routine to Main to avoid error on my end while saving my work.  Then I created a separate little function to deal with unit conversions.  And I'm only incorporating it into the main code for use with Double type variables.  This may, or may not work, since your double values don't have any decimal point portions to them.  They may be understood as Integer (System.Int32) instead, in which case you would have to change that little If...Then block that used that conversion function.

Here's the code:

Sub Main
	Dim inAIV As Integer
	Dim inAIH As Integer
	Dim dBAI As Double
	Dim dTAI As Double = 268 mm 
	Dim dSAI As Double = 268 mm
	Dim dTerskelHøyde014 As Double = Parameter("LMV - SK5-014:1", "Hengsleside")
	
	If Terskel = "Kvilldal" Then
			dBAI = 250 mm
	Else If Terskel = "014" Then
			dBAI = dTerskelHøyde014 + 235 mm
	End If 
	
	If AntInfV <> 0 Then
		inAIV = AntInfV
	Else
		inAIV = Math.Ceiling((KarmHøyde - dBAI - dTAI) / 530 mm ) + 1
	End If
	
	
	If AntInfH <> 0 Then
		inAIH = AntInfH
	Else
		inAIH = Math.Ceiling((KarmBredde - 2 * dSAI) / 530 mm ) + 1
	End If
	
	Logger.Debug("BAI =" & dBAI)
	Logger.Debug("SAI =" & dSAI)
	Logger.Debug("nAIV =" & inAIV)
	
	Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
	
	'assemble list of name / value pairs (parameter name / parameter's intended value)
	Dim oPairs As New Dictionary(Of String, Object)
	oPairs.Add("nAIV", inAIV)
	oPairs.Add("BAI", dBAI)
	oPairs.Add("TAI", dTAI)
	oPairs.Add("SAI", dSAI)
	oPairs.Add("nAIH", inAIH)
	
	For Each oRefDoc As Document In oADoc.AllReferencedDocuments
		If oRefDoc.DocumentType <> DocumentTypeEnum.kPartDocumentObject Then Continue For	'skip if not part document
		Dim oPDoc As PartDocument = oRefDoc
		Dim oParams As Parameters = oPDoc.ComponentDefinition.Parameters
		Dim oParam As Inventor.Parameter
		For Each oParam In oParams
			For Each oPair As KeyValuePair(Of String, Object) In oPairs
				If oParam.Name = oPair.Key Then
					If TypeOf oPair.Value Is Double Then
						oParam.Value = ToMM(oPair.Value)
					Else
						oParam.Value = oPair.Value
					End If
					Logger.Debug("Para " & oPair.Key & " = " & oPair.Value.ToString)
				End If
			Next
		Next
	Next

	Logger.Debug("BAI =" & dBAI)
	Logger.Debug("SAI =" & dSAI)
	Logger.Debug("nAIV =" & inAIV)
End Sub

Function ToMM(oInputValue As Double) As Double
	'to convert 'database' distance units (centimeters) to millimeters
	ToMM = ThisApplication.UnitsOfMeasure.ConvertUnits(oInputValue, UnitsTypeEnum.kDatabaseLengthUnits, UnitsTypeEnum.kMillimeterLengthUnits)
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) 👍.

If you want and have time, I would appreciate your Vote(s) for My IDEAS 💡or you can Explore My CONTRIBUTIONS

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 6 of 6

fridtjofZM5ME
Collaborator
Collaborator
Accepted solution

@WCrihfieldThanks a lot! The function did the trick, but I had to convert the oInputValue to database length units, not the other way around (At least I think that is what I did) by swapping the last two statements in the ToMM expression.

Function ToMM(oInputValue As Double) As Double
	'to convert 'database' distance units (centimeters) to millimeters
	ToMM = ThisApplication.UnitsOfMeasure.ConvertUnits(oInputValue, UnitsTypeEnum.kMillimeterLengthUnits, UnitsTypeEnum.kDatabaseLengthUnits)
End Function

 

0 Likes