Overlay Graphics

Do you need to allow the user to select a screen position? Would you like to provide some feedback as they move the cursor around the screen?
If so, the SpecifyScreenPosition function and the overlay graphics primitives are just what you need. The SpecifyScreenPosition function allows you to define a "motion callback function" that will be called each time a mouse movement is detected. If you have created any Windows forms applications, this would be very similar to the MouseMove event. The motion callback works with Overlay Graphics Primitives (OGP) to allow for some cool graphical effects that are very useful for user feedback. Think about using a selection rectangle or lasso in NX; there is visual feedback regarding the size and position of the selection method, but they are just temporary objects - you don't end up with four new lines in your part file each time you use a selection rectangle.


So how does it work?

The SpecifyScreenPosition function allows you to supply a function of your design that it will call each time the mouse is moved. Within this motion callback, you can call special functions that draw lines, arcs, circles, and polylines using what are known as Overlay Graphics Primitives. The OGP's are special temporary objects in NX that know how to clean themselves up. Each time the motion callback function executes, the OGP's are removed from the screen before new ones are created. This can create a relatively smooth animation effect while the user is deciding on a position to use. Usually, when doing animation such as this, the programmer has to clean up any temporary objects before creating the new ones; but here, the NXOpen API takes care of the hard work for us.


An Example

Let's imagine that you want to create a circle of a given size at a position of the user's choosing. The journal below will show a circle of the desired size that moves around with the cursor as the user decides where to place it. When the user clicks to confirm their choice, an actual arc object will be created at the specified position.




'NXJournaling.com
'October 7, 2014
'
'Overlay graphics demo with SpecifyScreenPosition function:
'Give the user visual feedback when picking a point on the screen.
'
Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF

Module overlay_graphics

Dim theSession As Session = Session.GetSession()
Dim theUI As UI = UI.GetUI()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim lw As ListingWindow = theSession.ListingWindow

Dim workPart As Part = theSession.Parts.Work

Const inchCircleDia As Double = 2
Const mmCircleDia As Double = 50

Dim circleDia As Double
Dim circleOrientation(8) As Double

Sub Main()

If IsNothing(theSession.Parts.Work) Then
'active part required
Return
End If

lw.Open()

If workPart.PartUnits = BasePart.Units.Inches Then
circleDia = inchCircleDia
Else
circleDia = mmCircleDia
End If

Const undoMarkName As String = "NXJ overlay graphics demo"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, undoMarkName)

'move the WCS to absolute (to keep our example simple)
Dim absXform As Xform = workPart.Xforms.CreateXform(SmartObject.UpdateOption.WithinModeling, 1)
Dim absCsys As CartesianCoordinateSystem = workPart.CoordinateSystems.CreateCoordinateSystem(absXform, SmartObject.UpdateOption.WithinModeling)
Dim csys3 As CartesianCoordinateSystem = workPart.WCS.SetCoordinateSystemCartesianAtCsys(absCsys)

'define the orientation of our circle object to lie on the absolute XY plane
circleOrientation(0) = 1
circleOrientation(1) = 0
circleOrientation(2) = 0
circleOrientation(3) = 0
circleOrientation(4) = 1
circleOrientation(5) = 0
circleOrientation(6) = 0
circleOrientation(7) = 0
circleOrientation(8) = 1

Dim selectedPoint(2) As Double
selectedPoint = SelectScreenPoint()
If IsNothing(selectedPoint) Then
Return
End If

Dim theCenPt As New Point3d(selectedPoint(0), selectedPoint(1), selectedPoint(2))
DrawCircle(theCenPt, circleDia / 2)

lw.Close()

End Sub

Function SelectScreenPoint() As Double()

'Allow user to interactively pick the point where the circle
'will be placed.

'This Function needs Sub MotionCallback() to work properly.

Dim myScreenPos(2) As Double
Dim theViewTag As Tag = theSession.Parts.Display.Views.WorkView.Tag
Dim theResponse As Integer

theUfSession.Ui.LockUgAccess(UFConstants.UF_UI_FROM_CUSTOM)

theUfSession.Ui.SpecifyScreenPosition("pick a point", AddressOf MotionCallback, Nothing, myScreenPos, theViewTag, theResponse)

theUfSession.Ui.UnlockUgAccess(UFConstants.UF_UI_FROM_CUSTOM)

If theResponse = UFConstants.UF_UI_PICK_RESPONSE Then
Return myScreenPos
Else
Return Nothing
End If

End Function

Sub MotionCallback(ByVal pos() As Double, _
ByRef motion_cb_data As UFUi.MotionCbData, _
ByVal client_data As System.IntPtr)

'This sub will be called every time a cursor move is detected during the
'SpecifyScreenPosition function.

'The parameters motion_cb_data and client_data are not used in this implementation,
'but the Sub must have the same signature as UFUI.MotionFnT to work properly.

'draw temporary circle for visual cue
theUfSession.Disp.DisplayOgpCircle(theSession.Parts.Display.Views.WorkView.Tag, circleOrientation, pos, circleDia / 2)

'also see:
' DisplayOgpArc
' DisplayOgpLine
' DisplayOgpPolyline

End Sub

Sub DrawCircle(ByVal centerPoint As Point3d, ByVal radius As Double)

Dim origin1 As Point = workPart.Points.CreatePoint(centerPoint)

Dim nullFeatures_AssociativeArc As Features.AssociativeArc = Nothing

Dim associativeArcBuilder1 As Features.AssociativeArcBuilder
associativeArcBuilder1 = workPart.BaseFeatures.CreateAssociativeArcBuilder(nullFeatures_AssociativeArc)

With associativeArcBuilder1

.Type = Features.AssociativeArcBuilder.Types.ArcFromCenter
.Limits.FullCircle = True
.CenterPoint.Value = origin1
.EndPointOptions = Features.AssociativeArcBuilder.EndOption.Radius
.Radius.RightHandSide = radius.ToString
.Associative = False

End With

Dim nXObject1 As NXObject
nXObject1 = associativeArcBuilder1.Commit()

Dim objects1() As NXObject
objects1 = associativeArcBuilder1.GetCommittedObjects()

associativeArcBuilder1.Destroy()

End Sub

End Module




Under the Hood

Shown below is the definition of the SpecifyScreenPosition function taken from the API help file:

Public Sub SpecifyScreenPosition ( _
message As String, _
motion_cb As UFUi.MotionFnT, _
motion_cb_data As IntPtr, _
screen_pos As Double(), _
ByRef view_tag As Tag, _
ByRef response As Integer _
)


Let's take a look at each of the parameters.

  • message: text that will be shown in the NX prompt area (input)
  • motion_cb: the motion callback function that we want to call during the selection process (input)
  • motion_cb_data: any information that you need to pass into the motion callback function (input)
  • screen_pos: an array of doubles representing the point picked by the user (output)
  • view_tag: the tag of the view in which you want to perform the selection (output)
  • response: an integer value representing the action taken by the user (did the user pick a point, or press cancel?) (output)

If you'd like to use the SpecifyScreenPosition function but do not need to use the callback functionality, pass null values (the Nothing keyword in VB.net) for the motion_cb and motion_cb_data. But since you are the more adventurous sort, let's take a closer look at using the callback function. For the motion_cb, it appears we need to pass in an object of type UFUi.MotionFnT; so what is that exactly? The motion callback function must have a very specific list of parameters; the SpecifyScreenPositon function is programmed to work with particular input/output. The UFUi.MotionFnT defines what the signature of our motion callback function must be. Below is the definition of the UFUi.MotionFnT:

Public Delegate Function MotionFnT ( _
screen_pos As Double(), _
ByRef motion_cb_data As UFUi.MotionCbData, _
data As IntPtr _
) As Void

All of the arguments are inputs to the function, these inputs will be provided by the SpecifyScreenPosition function. Our callback function must accept the exact same arguments or errors will occur. The function is defined as Void, which simply means it will not return a value; we'll use a subroutine in our VB implementation rather than a function.

  • screen_pos: an array of double values representing the current location of the cursor
  • motion_cb_data: a structure containing information on which view the cursor is in and the start position of the cursor
  • data: this is a reference to the motion_cb_data that we passed to the SpecifyScreenPosition function



So each time the SpecifyScreenPositon function detects a movement of the mouse, it will call our callback function and pass in the new position of the cursor, information about the view, and any custom data that we originally gave to it. Of these values, screen_pos is the most important; it is the only one required to make use of the overlay graphics and in the simple example above it is the only value that is used.



Ignoring the comments in the MotionCallback subroutine, we see that it boils down to a single line of code: the one that draws the overlay graphics primitive.


Sub MotionCallback(ByVal pos() As Double, _
ByRef motion_cb_data As UFUi.MotionCbData, _
ByVal client_data As System.IntPtr)

theUfSession.Disp.DisplayOgpCircle(theSession.Parts.Display.Views.WorkView.Tag, circleOrientation, pos, circleDia / 2)

End Sub

Most of the inputs to the DisplayOgpCircle function are module level variables defined elsewhere in the journal. Using module level variables is a quick way to access needed information in the MotionCallback function; the alternative is to use the client_data which involves marshaling memory locations which is beyond the scope of this article. The pos variable is an array of values representing the current cursor location, this point is used as the center point of the OGP circle. The example only makes one call to an OGP function, but you can use several calls to create more complex shapes such as polygons, stars, smiley faces, or whatever else you can come up with. However, bear in mind that the MotionCallback function may be called many times during the journal execution and must run quickly to keep a responsive feel. You will want to minimize the amount of processing done in the MotionCallback subroutine to maximize execution speed.

Conclusion

Providing some visual feedback to the user during a selection process can greatly improve the usability of your journal. Consider using overlay graphics primitives along with the SpecifyScreenPosition function when you need to place objects or symbols.

Comments

There's a dialog box which opens once our drawing sheet is loaded.How can we avoid this dialog box?..I just want to directly place my circle without that dialog box.

The dialog box is part of the Ui.SpecifyScreenPosition function and cannot be avoided. It gives the user the opportunity to cancel the operation or select a point by name.

Please tell me if there is any way to hide it..I just don't want to display that box.

I understand that it cant be avoided..Is there any way atleast to hide the dialog box?

I'm not aware of any way to hide the dialog box used by the .SpecifyScreenPosition function. Perhaps there is an alternative function that you could use, but offhand, I don't know what it would be.

I have used select a point method and have selected one of the points on the Part on a drawing View..How can I know the name of the point selected?..lyk Point (4) or point(5)?

If you have a reference to a point feature, you can get the name as shown in the part navigator by using the .GetFeatureName method.

I am using SpecifyScreenPosition function to locate a Notebox in Nx 8.5..I am able to locate this box evrywhere in the drawing view except on the drawing views such as front view,back view etc..I am not able to understand what exactly is wrong with this method.Please help me out

From your description it is difficult to tell what output you desire versus what you are getting. Are there any error messages returned? What exactly are you trying to accomplish?

Perhaps posting your code (or a relevant part of it) would help.

In the Above example,Circle has been displayed whenever the cursor moves..It has been done by using DisplayOgpCircle method..How can I display Tabular Note..I am not able to find suitable API methods available

Query the tabular note to find its size, then use four calls to DisplayOgpLine to display its outline.

I did not understand you correctly..Plz can u tell me in detail:

Dim secPrefs As UFTabnot.SectionPrefs
ufs.Tabnot.AskDefaultSectionPrefs(secPrefs)
Dim cellPrefs As UFTabnot.CellPrefs
ufs.Tabnot.AskDefaultCellPrefs(cellPrefs)
ufs.Tabnot.SetDefaultCellPrefs(cellPrefs)
Dim origin(2) As Double
origin(0) = loc.X
origin(1) = loc.Y
origin(2) = loc.Z
Dim tabnote As NXOpen.Tag
ufs.Tabnot.Create(secPrefs, origin, tabnote)

This is what I have used to create Tabular Note;Now while I am using SpecifyScreenPosition() method to locate tabularNote,I want to display tabular note around the cursor.

Since you know how large your tabular note will be, you can call the DisplayOgpLine function four times in your motion callback to draw a rectangle that approximates the size of the note. For an example of drawing a rectangle with DisplayOgpLine function calls, see Sub MotionCallback in the posted code:
http://nxjournaling.com/content/placing-dimension-break

Thanks a lot for the link..But I am just a beginner..Not able to clearly understand the code:

I have written this..Whats wrongs here?
I am getting internal memore problem when I compiled this.
Dim pos1() as Double
Dim pos2() as double

pos1(0)=10
pos1(1) = 0
pos2(0) = 40
pos2(2) = 0
pos1(2) = 0
pos2(2) = 0
theUfSession.Disp.DisplayOgpLine(theSession.Parts.Display.Views.WorkView.Tag, pos1, pos2)

The error probably has to do with the fact that you never assign a value to "pos2(1)".

Dim UserselectedPoint(2) As Double
UserselectedPoint = SelectScreenPoint()
If IsNothing(UserselectedPoint) Then
Return
End If

Inside the motion callback function:

pos1(0)=10
pos1(1) = 0
pos2(0) = 40
pos2(1) = 0
pos1(2) = 0
pos2(2) = 0
theUfSession.Disp.DisplayOgpLine(theSession.Parts.Display.Views.WorkView.Tag, pos1, pos2)

Will this be fine Or I need to specify 2nd and 3rd terms only in terms of Pos()..Pos is the first parameter inside Motioncallback function.

yeah I will post my code tomorrow definitely as I dont have it now...Meanwhile can u plz share your skype name..I would like to discuss some other things in Journal

In a drawing sheet,we have different views like Front View,Back view,Side view etc.(Total 6 views)..When I am using SpecifyScreenPosition to locate TabularNote in Drawing sheet other than views,then it is placed according to cursor location but when the tabularNote is placed at views,then the location is not same as cursor ..I hope you understand

When I run the code above, a circle is correctly created on the drawing at the pick point whether the selected point is inside of a drawing view or outside of a view.

What result do you get?

I am not able to get in the drawing views..In drawing sheet,it is coming correctly.I have been working on this from past 1 week.
Please provide me your email id...I would like to send you my full code.

You can send the code to: info@nxjournaling.com

I have checked out with various things like Note,tabular Note etc..I am not able to place any of these exactly on the drawing view..Please help me.

I have written the following code to locate the position of Tabular Note in a drawing sheet:

Dim UserselectedPoint(2) As Double
UserselectedPoint = SelectScreenPoint()
If IsNothing(UserselectedPoint) Then
Return
End If

Dim TabularNotePos As New Point3d(UserselectedPoint(0), UserselectedPoint(1), UserselectedPoint(2))

The coordinates of the Drawing sheet are different from Drawing view:This is so called global and local coordinates concept.
Please help me in solving this..I need to locate my tabularNote correctly.

I have written the following code:
Dim featurescollection() As Features.Feature
featurescollection = workPart.Features.GetFeatures()
Dim pointFeature1 As Features.PointFeature = Nothing
Dim featurecoord As Point3d = featurescollection(0).Location
Dim featurecoordX As String = FormatNumber(featurecoord.X, 1).ToString()
Dim featurecoordY As String = FormatNumber(featurecoord.Y, 1).ToString()
Dim StringfeaturecoordZ As String = FormatNumber(featurecoord.Z, 1).ToString()
MsgBox("X :" & featurecoordX & "," & featurecoordY & "," & StringfeaturecoordZ)

This code displays X,Y,Z coordinates of datumcoordinate system(0)..It gives (0,0,0)..I want to know these coordinates values in the Global coordinate system i.e according to coordinates system of drawing sheet.

I am able to Display Tabular Note in Motion Callback function using DisplayOgpLine method,but if I want to directly display default Tabular Note ..how is it possible?..I believe We can display any symbol..Plz correct me If I am wrong

To the best of my current knowledge, it is not possible to "directly display any symbol". I'd love to learn of such a method; if you find one, please post the details.

Now,I am even able to display Tabular Note directly..I am posting my code to your mailbox..Please check it..I will mention evrything in the mail.

I'm hoping to find a way to display a text string at a fixed position on the screen and always normal to the current view. Is that possible? I want to be able to display a string attribute of the file on the screen as a reference, and be able to turn it on and off. I've seen journals that display the name of an object, always normal to the view, so I am hoping that this is something that is near to an existing solution. Thanks.

RVogel

The function .DisplayTemporaryText may do what you need. One example can be found on eng-tips:
http://www.eng-tips.com/viewthread.cfm?qid=359347

Hello NXJournaling, I just went through your tutorial on the SpecifyScreenPosition function. Let's say I do not want to use the motion callback function and instead of selecting the screen position by cursor pick, is it possible to use the point which i have already selected. So, i pass on null values for the callback function. How can i use this function to get the screen position of the selected point without having the location picked by the cursor. I intend to hard code the response value (as integer 1) to fake the cursor pick action. Is it doable by this approach..??

Balaji

It isn't necessary to use the motion callback option of the specify screen position function. In this case, the call would look something like:

theUfSession.Ui.SpecifyScreenPosition("pick a point", Nothing, Nothing, myScreenPos, theViewTag, theResponse)

"...fake the cursor pick action."

However, if you already have the coordinates of a point, I'm not sure why you need the specify screen position function at all?

What exactly are you trying to do?

hi, i do not have the coordinates of the point. I have only the points and i want to find the location of the points w.r.t the sheet coordinates for positioning the labels. This is related to my other post, where you have provided me with the sample code using .MapModelToDrawing. I find it difficult to understand how the functions are working in the sample code below.
http://www.nxjournaling.com/comment/5869#comment-5869
I came across this method SpecifyScreenPosition in the same journal and read your tutorial on the same. I found this SpecifyScreenPosition relatively simpler and i was thinking if I could use this function to get the sheet coordinates of the point without having the location picked on the screen.

Balaji