Expressions: create an expression with units

Now that we have seen how to create expressions and have learned about the units available in NX, we can easily create expressions that use units.

Bare Bones Code

To create an expression with units, we will first need references to a unit object and an expression object. Once we have the necessary references, we can call the expression collection's .CreateWithUnits method, supplying a name and numerical value for the new expression.

Option Strict Off
Imports System
Imports NXOpen

Module NXJ_exp_unit_1

Sub Main(ByVal args() As String)

Dim theSession As Session = Session.GetSession()
Dim workPart As Part = theSession.Parts.Work

Dim unit1 As Unit = CType(workPart.UnitCollection.FindObject("MilliMeter"), Unit)

Dim expression1 As Expression
expression1 = workPart.Expressions.CreateWithUnits("test=25", unit1)

End Sub

End Module

The code above is short and to the point in part because it does no error checking. If you try to run the code again on the same part (or if you attempt to run the code on a part that already has an expression named "test") you will be met with an error; NX will not create a new expression that has the same name as an existing expression. Let's add some error handling and some expression name/value variables in the next version.

Improved code

Before running the code below, start a new file with the base units of "inch". The code will create a new expression named "test" with a value of 25 mm as before, but we'll explore an important difference when the part units and the expression units do not match.


Option Strict Off
Imports System
Imports NXOpen

Module NXJ_exp_unit_1

Sub Main(ByVal args() As String)

Dim theSession As Session = Session.GetSession()
Dim lw As ListingWindow = theSession.ListingWindow
Dim workPart As Part = theSession.Parts.Work

lw.Open()

Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "NXJ expression with units")

Dim unit1 As Unit = CType(workPart.UnitCollection.FindObject("MilliMeter"), Unit)

Dim expression1 As Expression
Dim myExpName As String = "test"
Dim myExpValue As Double = 25

lw.WriteLine("myExpName = " & myExpName)
lw.WriteLine("myExpValue = " & myExpValue.ToString)
lw.WriteLine("")

Try
'create expression, type: Number, measure: length, units: mm
expression1 = workPart.Expressions.CreateWithUnits(myExpName & "=" & myExpValue.ToString, unit1)
lw.WriteLine("expression created: '" & expression1.Name & " = " & expression1.RightHandSide & "'")

Catch ex As NXException
If ex.ErrorCode = 1050017 Then
'The specified expression variable already exists.
expression1 = workPart.Expressions.FindObject(myExpName)

'**************************************************************************************
'Option 1
'the following line will set the value of the expression in the units of the expression
expression1.RightHandSide = myExpValue.ToString
'**************************************************************************************

'****************************************************************************
'Option 2
'the following line will set the value of the expression in base (part) units
'probably not what you want, but useful in certain circumstances
'expression1.Value = myExpValue
'****************************************************************************

lw.WriteLine("existing expression updated: '" & expression1.Name & " = " & expression1.RightHandSide & "'")

Else
'other error
lw.WriteLine("NX exception: " & ex.ErrorCode & ", " & ex.Message)

End If

End Try

lw.Close()
End Sub

End Module

The code above wraps the call to .CreateWithUnits in a Try Catch block to handle the error that occurs if we try to create an expression with the same name as an existing expression. If the "expression variable already exists" error occurs (error 1050017), we find the existing expression and edit that one instead of making a new expression. The journal writes our input values to the information window and also writes the name and value of the created/edited expression object.

Now comment out the line of code in "option 1" and uncomment the corresponding line of code in "option 2" and rerun the journal. If the base units of the part is inches, you will see an important difference. The reported input value will be 25, as expected; but the reported value of the expression will be 635. What happened? In option 1, we used the .RightHandSide property of the expression. This would be equivalent to typing in a number to the formula input in the expression dialog; the number entered was interpreted to be in the same units as the expression. In option 2, we updated the expression's .Value property. According to the help files, the .Value property will "return or set the value of the expression in base units". In our case, the base units are inches (the units of the part file); the value of 25 was interpreted as "inches" and the value was converted to the expression units (25 inches = 635 mm). Moral of the story, make sure that you know when the value is being converted and when it isn't; unit conversion mistakes can be very costly!

Converting Units

We looked at converting units in the article about the NX Unit object. We can use some of that know how here to convert an expression from one unit to another. On the first run, the following journal will create an expression named "test2" with a value of 12 inches. On the following run, the journal will convert the expression units from inches to centimeters.


Option Strict Off
Imports System
Imports NXOpen

Module NXJ_exp_unit_2

Sub Main(ByVal args() As String)

Dim theSession As Session = Session.GetSession()
Dim lw As ListingWindow = theSession.ListingWindow
Dim workPart As Part = theSession.Parts.Work

lw.Open()

Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "NXJ convert expression units")

Dim unit1 As Unit = CType(workPart.UnitCollection.FindObject("Inch"), Unit)
Dim unit2 As Unit = CType(workPart.UnitCollection.FindObject("CentiMeter"), Unit)

Dim expression1 As Expression
Dim myExpName As String = "test2"
Dim myExpValue As Double = 12

lw.WriteLine("myExpName = " & myExpName)
lw.WriteLine("myExpValue = " & myExpValue.ToString)
lw.WriteLine("")

Try
'create expression, type: Number, measure: length, units: mm
expression1 = workPart.Expressions.CreateWithUnits(myExpName & "=" & myExpValue.ToString, unit1)
lw.WriteLine("expression created: '" & expression1.Name & " = " & expression1.RightHandSide & " " & expression1.Units.Abbreviation & "'")

Catch ex As NXException
If ex.ErrorCode = 1050017 Then
'The specified expression variable already exists.
expression1 = workPart.Expressions.FindObject(myExpName)

lw.WriteLine("expression1.Units: " & expression1.Units.Abbreviation)
lw.WriteLine("target units: " & unit2.Abbreviation)
lw.WriteLine("")

If expression1.Units.Equals(unit2) Then
lw.WriteLine("no need for conversion")
Exit Sub
End If

lw.WriteLine("convert expression units from " & expression1.Units.Abbreviation & " to " & unit2.Abbreviation)
lw.WriteLine("before conversion: " & expression1.Name & " = " & expression1.RightHandSide & " " & expression1.Units.Abbreviation)

Dim theValue As Double
If Double.TryParse(expression1.RightHandSide, theValue) Then
expression1.RightHandSide = workPart.UnitCollection.Convert(expression1.Units, unit2, theValue).ToString
expression1.Units = unit2

lw.WriteLine("after conversion: " & expression1.Name & " = " & expression1.RightHandSide & " " & expression1.Units.Abbreviation)

End If

Else
'other error
lw.WriteLine("NX exception: " & ex.ErrorCode & ", " & ex.Message)

End If

End Try

lw.Close()
End Sub

End Module

Conclusion

The NXOpen API gives us the necessary tools for creating expressions and converting units; however, it is easy to make mistakes while doing so. Be sure to check that input data in your programs and thoroughly test your code! Even the improved example above isn't foolproof. It is too optimistic and assumes that the existing expression has matching units and is the one we really want to edit. It could be that the part we are working on has an existing string expression with the same name that we chose. We should really check the expression type before we attempt an edit. To keep the sample code short and to the point, such checks are not performed.