How I stopped worrying and learned to love the help file

Or, How to become an alchemist in 6 easy steps

Clear instructions can ease the most difficult of tasks; conversely, even a simple task is frustratingly difficult when you don’t know where to start. If you have had an idea for a journal, but the commands were not supported by the journal recorder; chances are good you have experienced such frustration. As an absolute last resort (c’mon admit it!), you open the help file, net_ref.chm and feel as if you have just opened the Emerald Tablet; you glimpse a wealth of knowledge hiding behind a wall of impenetrable language.

I’ve developed a sort of strategy when using the help file. It is not a perfect system and I’m constantly looking for ways to improve it, but as of right now, here it is:

  1. Try to record a journal.
  2. Use the search (or index) function to look up the object (class) you are interested in.
  3. Use the search (or index) function to look up the builder for the object you are interested in.
  4. Step through the process in interactive NX to look for new, relevant search terms.
  5. Use the search function and look at the top returned items.
  6. Browse through the UF section of the help file.

As an example, I was working on a journal that would identify any and all dimensions that had their values overridden with manual text. To find these in interactive NX, you can go to Information -> Other -> Object-specific... then choose Dimensions with Manual text. This will highlight all the dimensions that have manual text.

Using the steps outlined above gave the following results:

  1. The journal recorder did not produce anything useful. When the journal recorder produces code, you can either edit the output to get what you want or at least pick out some key words to search for in the help file to get more information (the class names of the objects it creates are good terms to search on).
  2. Knowing from previous experience there is a Dimension class, I looked it up with the index function. From here I found the .GetDimensionText and .SetDimensionText methods but I could find nothing that would indicate if the text was automatic or manual.
  3. The DimensionBuilder has its own properties and methods, but again, nothing that would indicate if the text was manual.
  4. In interactive NX, I used Information -> Object to inspect a few dimensions (some with automatic text and some with manual text). The first value in the OBJECT SPECIFIC INFORMATION section is Text Placement. Initially I thought this referred to the dimension style options of automatic placement, manual placement - arrows in, and manual placement - arrows out; but I noticed for all the manual dimensions this was reported as “Manual Text” and for the automatic dimensions this was reported as “Automatic Text”. Back in the Dimension class entry in the help file, if you follow the .GetDimensionPreferences link through to the DimensionPreferences class you will see a .TextPlacement property. This .TextPlacement property refers to the dimension style options mentioned earlier and not to automatic or manual text as the information window does. I think it is simply a case of poor wording in the information window (at least in the english version of NX).
  5. I used the search function and entered the term manual text. The search returns 55 topics, many of which look like they are CAM related. So, ignoring such topics as DrillBurnishingToolBuilder class, leaves about 20 topics to look through. Many of these remaining topics start with uf_, which indicates it is in the older UF documentation. It is preferred to use the .NET function if one exists that does what you want. You can use the UF functions, but in general they are a bit trickier to use. Many of the uf_ topics are quite large; to search within a topic hold down the control key and press the F button. This will bring up a Find dialog box that will allow you to search within the topic. Searching within uf_drf turns up functions that allow you to retrieve the dimension text and change the dimension text and most interestingly, a description of a 100 element array called mpi that holds information about a dimension. Item 7 in this list (actually item 8 since the array is zero based, but we’ll ignore that for now) is TEXT ENTRY MODE, and in the description it states: “For UF_DRF_ask/set_object_preferences, this only reports or sets the text to be manual or automatic. It does not report whether the object has appended text.” Score! Now we just need some more information on this UF_DRF_ask_object_preferences function.
  6. Fortunately it didn’t come to this, but as a last resort I’d open up the Contents tab of the help file and start poking around the User Function Reference section (specifically the drafting and/or drawing section, for the given example). This is a tedious process but you may stumble upon something interesting that you can make use of in the future. When I run across such a gem, I take a screenshot (of at least the function name and description) and file it away for future reference - Microsoft OneNote is fabulous for this purpose.
     

Searching on uf_drf_ask_object_preferences returns four topics, one of which is AskObjectPreferences Method. This is the .NET wrapper for the UF function, the function signature is below:

Public Sub AskObjectPreferences ( _
    drf_object_tag As Tag, _
    <OutAttribute> mpi As Integer(), _
    <OutAttribute> mpr As Double(), _
    <OutAttribute> ByRef radius_val As String, _
    <OutAttribute> ByRef diameter_val As String _
)

What this tells us is when we call the function, we need to pass in five variables; those marked <OutAttribute> will be used to return information from the function (we will pass in empty variables for the function to use as output). So, we’ll have to pass in the tag of the dimension we are interested in (drf_object_tag), an array of integers (mpi), an array of doubles (mpr), and two string variables (radius_val and diameter_val). The help file politely provides a link to the UF_DRF_ask_object_preferences documentation; following this link we learn that the integer array needs to be 100 elements and the double array needs to be 70 elements. Following the “drafting parameters” link brings us back to a description of what the returned array values mean. The array value at offset 7 (mpi(7)) represents the text entry mode and can take on 1 of 4 values:

1 = Only automatic text
2 = Automatic text, with appended text
3 = Only manual text
4 = Manual text, with appended text

Pulling all this information together leads to the following key lines of code:
[vbnet]
ufs.Drf.AskObjectPreferences(partDimension.Tag, mpi, mpr, radius_value, diameter_value)

If mpi(7) = 3 OrElse mpi(7) = 4 Then

'dimension has manual text

'do something with it
End if
[/vbnet]

The entire journal is shown below:

[vbnet]
'NXJournaling.com
'May 31, 2012
'When run, the journal will highlight all dimensions in the part that have manually entered text.
'The listing window will report the dimension text, view, and sheet for each dimension
'with manually entered text.

Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF

Module Report_Dimensions_manual_text

Sub Main()

Dim theSession As Session = Session.GetSession()
Dim ufs As UFSession = UFSession.GetUFSession()
Dim workPart As Part = theSession.Parts.Work
Dim displayPart As Part = theSession.Parts.Display
Dim lw As ListingWindow = theSession.ListingWindow
Dim mpi(99) As Integer
Dim mpr(69) As Double
Dim radius_value As String
Dim diameter_value As String
Dim manualTextCount As Integer = 0
Dim dictionary As New Collections.Generic.Dictionary(Of String, String)
Dim viewList() As View
Dim text1() As String
Dim text2() As String

lw.Open()

For Each sheet As Drawings.DrawingSheet In workPart.DrawingSheets
viewList = sheet.GetDraftingViews
For Each myView As View In viewList
dictionary.Add(myView.Name, sheet.Name)
Next
Next

Dim partDimensions() As Annotations.Dimension
partDimensions = workPart.Dimensions.ToArray
If partDimensions.Length > 0 Then
For Each partDimension As Annotations.Dimension In partDimensions
ufs.Drf.AskObjectPreferences(partDimension.Tag, mpi, mpr, radius_value, diameter_value)

If mpi(7) = 3 OrElse mpi(7) = 4 Then
'dimension has manual text
partDimension.Highlight()
lw.WriteLine("Sheet: " & dictionary(partDimension.GetAssociativity(1).ObjectView.Name))
lw.WriteLine("View: " & partDimension.GetAssociativity(1).ObjectView.Name)
partDimension.GetDimensionText(text1, text2)
Dim j As Integer
lw.WriteLine("Dimension Text: ")
For j = text1.GetLowerBound(0) To text1.GetUpperBound(0)
lw.WriteLine(" " & text1(j))
Next
manualTextCount += 1
lw.WriteLine("")
End If
Next
If manualTextCount > 0 Then
MsgBox(manualTextCount & " dimensions have manual text and have been highlighted")
Else
MsgBox("There are no dimensions with manual text in the part")
End If
Else
MsgBox("There are no dimensions in the work part")
End If

lw.Close()

End Sub

Public Function GetUnloadOption(ByVal dummy As String) As Integer

'Unloads the image when the NX session terminates
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination

End Function

End Module
[/vbnet]

The other bit of code I had some problems with was reporting which sheet a given dimension is on. I was hoping there was a property or method that would directly return what sheet the dimension is on. Looking at the Dimension class documentation didn’t turn up any such method, but while I was there I did find out how to return the view name the dimension is associated to. From there I was hoping the View class had a property or method to return the sheet it belonged to, but again, no such luck. However, while searching through the DrawingSheet class, I did find the .GetDrawingViews() method that returns a collection of views on the given sheet. Since I know the view name the dimension is associated to and all the view names on a given sheet, relating the dimension to the sheet is fairly easy. In fact, there are several viable options to relate the dimension and the sheet given the information we have. The solution I chose makes use of a dictionary object.

So what’s a dictionary object?

A physical dictionary is a large collection of pairs of items (words - definitions). If you wanted to recreate a physical dictionary in code, you could utilize a large 2 dimensional array.

[vbnet]
Dim myVirtualDictionary(1,1)
myVirtualDictionary(0,0) = "aardvark"
myVirtualDictionary(0,1) = "medium-sized, burrowing, nocturnal mammal native to Africa"
myVirtualDictionary(1,0) = "zebra"
myVirtualDictionary(1,1) = "several species of African equids (horse family) united by their distinctive black and white stripes"
[/vbnet]

myVirtualDictionary array would look something like this:
 

  column 0 column 1
row 0 word 1 definition 1
row 1 word 2 definition 2
... ... ...
row n word n definition n

We could now write code that would search for a given word in column 1 and return the definition from column 2. The dictionary object is a specialized 2 dimensional array that does the searching for you. The dictionary object holds key-item pairs. Each key in the dictionary must be unique, but the item value can repeat if needed. Each word in the dictionary would be a key, and the definition would be the item. Continuing with the virtual dictionary example, the dictionary object could hold the keys “rabbit” and “bunny” with the exact same definition for each, but it could not hold two keys each with the value of “bunny”.

Using a dictionary object to manage our virtual dictionary instead of a generic 2 dimensional array would look like this:

[vbnet]
Dim myDictionaryObject As New Collections.Generic.Dictionary(Of String, String)
myDictionaryObject.Add("aardvark", "medium-sized, burrowing, nocturnal mammal native to Africa")
myDictionaryObject.Add("zebra", "several species of African equids (horse family) united by their distinctive black and white stripes")

'retrieve a definition
Dim aardvarkDefinition as String
aardvarkDefinition = myDictionaryObject("aardvark")
[/vbnet]

Note: you can import the System.Collections.Generic namespace to minimize the amount of typing necessary when declaring a dictionary object. Since my journal only uses one dictionary object, I didn’t bother to do so.

Since we know each view name in the NX file will be unique, we will use those as the dictionary key values. We loop over each drawing sheet and get the collection of views on each sheet; the view is added to the dictionary as the key value and the sheet is set as the item value.

[vbnet]
For Each sheet As Drawings.DrawingSheet In workPart.DrawingSheets
viewList = sheet.GetDraftingViews
For Each myView As View In viewList
dictionary.Add(myView.Name, sheet.Name)
Next
Next
[/vbnet]

Now when we want to know the sheet that a given view is on we can ask the dictionary object:

[vbnet]
sheetName = dictionary(view.name)
[/vbnet]

That pretty much wraps it up for this time. I hope your future searches in the help file are more productive. Go forth and make good use of the Dictionary object! And who knows maybe you’ll even find a good use for the example journal.

As always, questions, comments, or suggestions for future articles can be sent to info@nxjournaling.com

Comments

I was attempting to look up TraceARay in the NXOpen .NET API Reference file, and went to click on "example" under
"See Also
Refer to example"
in the help files but this brought up a page that read: "This program cannot display the webpage". Any ideas why this might be happening?

DHuskic
Nx 9 VB

At a guess, I'd say that either there is a typo in the link or the content wasn't included in the help file. In either case, I'd suggest contacting GTAC to make them aware of it. Perhaps they could fix it and put out a new version.