Point3d and Point objects

The point is a fundamental object for 3D modeling. It is a simple object, so will serve well for learning purposes; but they are also useful because they are often required when creating more complex entities (lines, arcs, splines, etc).
Even more fundamental than a point object is the Point3d structure, the NXOpen representation of a 3D coordinate. The Point3d is a three element array of doubles which provides the programmer (that’s us) a convenient way to access the X, Y, and Z coordinate values along with a few useful methods. A Point3d is simply variable data in your journal; by itself it does not create a visible point object. It does not appear in the NX graphics window or as an object anywhere in the interactive display, for that matter.
The Point3d structure provides a constructor which allows you to assign values at the time the variable is declared.
[vbnet]'create Point3d using the constructor
Dim myPt1 As New Point3d(0, 0, 0)[/vbnet]
Alternatively, you can declare the variable and assign values later.
[vbnet]'create Point3d, then assign values
Dim myPt2 As Point3d
myPt2.X = 0
myPt2.Y = 0
myPt2.Z = 0[/vbnet]

Like many NXOpen objects, the Point3d structure has a .ToString method. This method will return a string representation of the object. In the case of a Point3d, it will return labeled coordinate information.
The .Equals method allows you to test if one object equals another; a boolean value of True or False is returned.
The .GetType method will return the type of the object it is used on. This is useful when you are cycling through objects in the file looking for a particular type. If you use .GetType.ToString() on a Point3d variable, the string value “NXOpen.Point3d” will be returned.
The .X, .Y, and .Z members can be used to get or set the respective coordinate data. In the myPt2 example above, the XYZ members were used to assign values to the Point3d. We can assign new values in the same way.

[vbnet]myPt2.X = 2.71
myPt2.Y = 3.14
myPt2.Z = myPt2.Y * 2[/vbnet]

Once a value is assigned, it can be used just like any other variable. You will notice the Z value above uses the Y value in its assignment.
Finally, the Point3d also provides the .GetHashCode() method. Hash codes are beyond the scope of this tutorial; but if you are interested, Wikipedia has a decent introductory article.

There is also a Point2d structure with all the methods and members of the Point3d structure, with the exception of the .Z member. As you may guess, this structure comes in handy for dealing with coordinates on the X-Y plane.

Below is a very short journal illustrating the use of the Point3d structure.

[vbnet]Option Strict Off
Imports System
Imports NXOpen

Module Points_01a

Sub Main()

Dim theSession As Session = Session.GetSession()
Dim rnd1 As New Random()
Dim lw As ListingWindow = theSession.ListingWindow

lw.Open()
'create Point3d using the constructor
Dim myPt1 As New Point3d(0, 0, 0)
'create Point3d, then assign values
Dim myPt2 As Point3d
myPt2.X = 0
myPt2.Y = 0
myPt2.Z = 0

'output point information
lw.WriteLine("myPt1: " & myPt1.ToString)
lw.WriteLine("myPt2: " & myPt2.ToString)
lw.WriteLine("myPt1 = myPt2 : " & myPt1.Equals(myPt2).ToString)
lw.WriteLine("myPt1.GetType.ToString: " & myPt1.GetType.ToString)
lw.WriteLine("")

'change values of myPt1 using random numbers
myPt1.X = rnd1.Next(-10, 10) + rnd1.NextDouble
myPt1.Y = rnd1.Next(-10, 10) + rnd1.NextDouble
myPt1.Z = rnd1.Next(-10, 10) + rnd1.NextDouble

'output new point information
lw.WriteLine("myPt1: " & myPt1.ToString)
lw.WriteLine("myPt2: " & myPt2.ToString)
lw.WriteLine("myPt1 = myPt2 : " & myPt1.Equals(myPt2).ToString)
lw.WriteLine("")

'show values of myPt1 rounded to 3 decimal places
lw.WriteLine(myPt1.X.ToString("[X=0.###;[X=-0.###") & "," & myPt1.Y.ToString("Y=0.###;Y=-0.###") & "," & myPt1.Z.ToString("Z=0.###];Z=-0.###]"))
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 NXOpen .NET API help file lists no less than 20 ways to create a point, considering that most of these methods can be used for creating a dumb point or an associative point feature, you’ll see that there is simply too much ground to cover in one tutorial. We’ll look at a basic method for creating dumb points and build on that in later tutorial(s).


Creating a dumb point with CreatePoint(Point3d)

[vbnet]Option Strict Off
Imports System
Imports NXOpen

Module Points_01b

Sub Main()

Dim theSession As Session = Session.GetSession()
Dim workPart As Part = theSession.Parts.Work
Dim rnd1 As New Random()
Dim lw As ListingWindow = theSession.ListingWindow
Dim newPt(1000) As Point
Dim max As Integer

lw.Open()
'lw.WriteLine(workPart.PartUnits.ToString)
If workPart.PartUnits = Part.Units.Inches Then
max = 10
Else 'metric file
max = 250
End If

'create Point3d using the constructor
Dim myPt1 As New Point3d(0, 0, 0)

'lw.WriteLine("max = " & max)

For i As Integer = 0 To 1000
'change values of myPt1 using random numbers
myPt1.X = rnd1.Next(-max, max) + rnd1.NextDouble
myPt1.Y = rnd1.Next(-max, max) + rnd1.NextDouble
myPt1.Z = rnd1.Next(-max, max) + rnd1.NextDouble
newPt(i) = workPart.Points.CreatePoint(myPt1)
newPt(i).SetVisibility(SmartObject.VisibilityOption.Visible)
newPt(i).Layer = rnd1.Next(1, 257)
Next

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 journal starts off by declaring some variables; all of the code is contained within Sub Main() so there are no module level variables declared. The notable declarations here are:
 Dim rnd1 As New Random()
Random is a class in the .NET framework used to generate random numbers. We'll use it to generate point coordinate data.

 Dim newPt(1000) As Point
Point is a class in the NXOpen API used to represent point objects.

The next section of code checks the part units (inch or millimeter) and sets the value of a variable named max accordingly. The max variable will be used to define a bounding cube for the points we generate.

The for loop creates the points. Coordinate data is generated by random numbers.
myPt1.X = rnd1.Next(-max, max) + rnd1.NextDouble
rnd1.Next(-max, max) returns a random integer in the range -max (inclusive) to max (exclusive); rnd1.NextDouble returns a random number between 0 (inclusive) and 1 (exclusive). The X, Y, and Z coordinate data for each point can then range anywhere within -max to max.
Each part file has a PointCollection object associated to it. It is through this object that we can query existing points and create new ones. CreatePoint(point3d) is a method of the PointCollection object, the following line of code accesses the point collection of the work part and creates the point... mostly
newPt(i) = workPart.Points.CreatePoint(myPt1)
The default visibility option for new points is "Invisible", not what we need for this journal. So...
newPt(i).SetVisibility(SmartObject.VisibilityOption.Visible)
makes our new point visible.
The following line assigns the point object to a random layer (1-256). If you don't specify properties such as color, layer, lineweight (not very useful for points), etc. they will be assigned the current default. All the points will be created in your current color (or default color for points if you have one specified) and if you comment out the layer assignment all the points will be created on your work layer. I assign the point to a random layer so that in the next journal we can see how to access and modify property values such as layer, color, etc.

Working with existing points

The following journal demonstrates how to work with existing points in a file. Run the previous journal that creates points before running this one.

[vbnet]Option Strict Off
Imports System
Imports NXOpen

Module Points_01c

Sub Main()

Dim theSession As Session = Session.GetSession()
Dim workPart As Part = theSession.Parts.Work
Dim lw As ListingWindow = theSession.ListingWindow
Dim max As Double
Dim myPoints() As Point
Dim pointsOnLayer(256) As Integer
Dim maxPoints As Integer
Dim maxLayer As Integer
Dim ptXYZ As Point3d

lw.Open()
'lw.WriteLine(workPart.PartUnits.ToString)
If workPart.PartUnits = Part.Units.Inches Then
max = 10
Else 'metric file
max = 250
End If

myPoints = workPart.Points.ToArray
For Each tempPoint As Point In myPoints
'if the layer number is odd, move point to next even numbered layer
If tempPoint.Layer Mod 2 > 0 Then
tempPoint.Layer += 1
End If

'keep track of how many points are on each layer
pointsOnLayer(tempPoint.Layer) += 1

'keep track of which layer has the most point objects
If pointsOnLayer(tempPoint.Layer) > maxPoints Then
maxPoints = pointsOnLayer(tempPoint.Layer)
maxLayer = tempPoint.Layer
End If

Next

'move first 2 points to opposite corners of bounding cube
ptXYZ = New Point3d(-max, -max, -max)
myPoints(0).SetCoordinates(ptXYZ)
myPoints(0).SetName("-max, -max, -max")
myPoints(0).Color = 1
myPoints(0).RedisplayObject()

ptXYZ = New Point3d(max, max, max)
myPoints(1).SetCoordinates(ptXYZ)
myPoints(1).SetName("max, max, max")
myPoints(1).Color = 1
myPoints(1).RedisplayObject()

'turn on name display for the work view
workPart.Preferences.NamesBorderVisualization.ObjectNameDisplay = Preferences.PartVisualizationNamesBorders.NameDisplay.WorkView

'move point to closest face of bounding cube
For i As Integer = 2 To myPoints.GetUpperBound(0)
ptXYZ = myPoints(i).Coordinates
If Math.Abs(ptXYZ.X) > Math.Abs(ptXYZ.Y) Then
'x is bigger
If Math.Abs(ptXYZ.X) > Math.Abs(ptXYZ.Z) Then
'x is bigger
myPoints(i).SetCoordinates(New Point3d(Math.Sign(ptXYZ.X) * max, ptXYZ.Y, ptXYZ.Z))
Else
'z is bigger
myPoints(i).SetCoordinates(New Point3d(ptXYZ.X, ptXYZ.Y, Math.Sign(ptXYZ.Z) * max))
End If
Else
'y is bigger
If Math.Abs(ptXYZ.Y) > Math.Abs(ptXYZ.Z) Then
'y is bigger
myPoints(i).SetCoordinates(New Point3d(ptXYZ.X, Math.Sign(ptXYZ.Y) * max, ptXYZ.Z))
Else
'z is bigger
myPoints(i).SetCoordinates(New Point3d(ptXYZ.X, ptXYZ.Y, Math.Sign(ptXYZ.Z) * max))
End If
End If
myPoints(i).RedisplayObject()
Next

'report the number of points on each even numbered layer
For i As Integer = 2 To 256 Step 2
lw.WriteLine("Points on Layer: " & i & " = " & pointsOnLayer(i).ToString)
Next
lw.WriteLine("")
'report which layer has the most point objects
lw.WriteLine("Max point count = " & maxPoints & " on layer: " & maxLayer)
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]

At the start of this journal, an empty array of point objects was created. The line:
myPoints = workPart.Points.ToArray
converts the point collection of the work part to an array of Point objects and assigns it to our array variable. We now have access to all the point objects in the current work part.

The For loop checks each point in the array. If the point object is on an odd numbered layer; the journal increases the layer number by one, moving it to the next higher even numbered layer. After the layer check the journal increments an array variable that keeps track of how many points are on each layer and it increments an integer variable that keeps track of the layer number that holds the most point objects.

The next group of statements demonstrates how to change the coordinates of an existing point, set the name property, and change the color. The .RedisplayObject() method forces an update so the changes can be seen, otherwise the changes may not be apparent until the system (or user) refreshed the display.

The following statment turns on the name display in the work view so you can see which points we have assigned names to.

The next For loop moves the point to the closest face of the bounding cube. The .SetCoordinates() method is used to change the existing points and the absolute value (.Abs) and sign (.Sign) methods of the .NET Math class are used.

Finally, some information on the point objects is output to the listing window.

Conclusion

In this tutorial we learned about the Point3d structure and how it can be used to create point objects. Along the way we learned a little about the PointCollection and part units of the work part, .NET random numbers, and a couple of .NET Math functions (.Abs and .Sign). I hope you learned something that will be useful in your future journals. If you have any specific questions, find any bugs, or have any comments please email them to info@nxjournaling.com or leave them in the comments section below.

Comments

can any one help me in creating a selection dialog for selection of snap points i.e., points on objects like end point,centre etc...please help me..its so urgent

Here is a code sample from GTAC, it may do what you need.

[vbnet]'Date: 03/23/2010
'Subject: Sample NX Open .NET Visual Basic program : select point with point constructor
'
'Note: GTAC provides programming examples for illustration only, and
'assumes that you are familiar with the programming language being
'demonstrated and the tools used to create and debug procedures. GTAC
'support professionals can help explain the functionality of a particular
'procedure, but we will not modify these examples to provide added
'functionality or construct procedures to meet your specific needs.

Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpenUI

Public Class select_point_with_point_constructor
Public Shared theUFSession As UFSession
Public Shared theSession As Session

Public Shared Sub Main(ByVal args As String())
theSession = Session.GetSession()
theUFSession = UFSession.GetUFSession()

Dim theUI As UI = UI.GetUI()

'Insert code here
Dim base_pt As Double() = New Double(2) {}
While select_point("Select Point", base_pt) = UFConstants.UF_UI_OK
theUI.NXMessageBox.Show("Selected Point", NXMessageBox.DialogType.Information, (("X:" & base_pt(0).ToString() & vbLf & "Y:") + base_pt(1).ToString() & vbLf & "Z:") + base_pt(2).ToString())

End While
End Sub

Public Shared Function select_point(ByVal cue As String, ByRef base_pt As Double()) As Integer
Dim point_tag As NXOpen.Tag = NXOpen.Tag.Null
Dim response As Integer = 0
Dim base_method As UFUi.PointBaseMethod = UFUi.PointBaseMethod.PointInferred

theUFSession.Ui.LockUgAccess(NXOpen.UF.UFConstants.UF_UI_FROM_CUSTOM)
theUFSession.Ui.PointConstruct(cue, base_method, point_tag, base_pt, response)
theUFSession.Ui.UnlockUgAccess(NXOpen.UF.UFConstants.UF_UI_FROM_CUSTOM)
Return response
End Function
End Class [/vbnet]

Is there something about the select_point function that limits it to select only one point? How could it be modified to return an array of points?

Thanks

Dave

DG

This is the same style dialog as when you are creating points (Insert -> Datum/point -> point), which has the same "one at a time" limitation.

If you need multiple points, I'd suggest creating a list before the loop and in the loop, add the newly defined point to your list. At the end of the code you will have a list of points to work with (which can easily be converted into an array, if needed).

Wow..dats great support...Thanks for your timely help..this is what exactly i've been trying to do..i'm glad that i didn't hesitated to join NX journalling.

          We have a provision in NX for checking the status of a sketch by unhiding the Column Status.It then gives status results like fully constrained,fully constrained with auto dimensioning,underconstrained etc..I want all that info into my listing window.i.e.,sketches status to be displayed exactly what it looks like in column Status.
       I have identified using activateSketch,GetStatus and Deactivate sketch methods.But the problem is, it is taking much time when my part has more number of sketches.So i need an alternate method to find status of sketch.Can this be done?..Please reply immidiately.

I know of no way to get the sketch status without first activating the sketch.
If you are simply checking the part to your site standards, I know there are some Knowledge Fusion (KF) part checks - checks for constrained sketches included. If you have access to a KF license (I do not) you might want to look into these part checks.

      I don't have KF license but still thanks for the information.

Hello,
I am trying to figure out how to get information for all the Routing Segments in the 3D.
I edited the code of "Working with existing points" , but it doesnt work.
Please help.
Thanks

Dim mySplines() As NXOpen.Routing.SplineSegment

lw.Open()

mySplines = workPart.NXOpen.Routing.SplineSegment.ToArray

For Each tempSpline As NXOpen.Routing.SplineSegment In mySplines
lw.WriteLine("length:" & tempSpline.Getlength() )
Next

lw.Close

Carlo Tony Daristotile

Forget it.
I figured it out.

Carlo Tony Daristotile

Hello,
Is it possible to find the location (x,y) of mouse picking on drafting?

Below is a quick example of picking a screen position.


Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UI

Module NXJournal
Sub Main()

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

lw.Open()

' Select the location
Dim location As Point3d
If pickScreenPosition(location)=Selection.Response.Cancel Then
exit sub
End If

lw.WriteLine(location.ToString)
lw.Close

End Sub

Function pickScreenPosition(ByRef location As Point3d) As Selection.Response

Dim ui As UI = GetUI()
Dim resp As Selection.DialogResponse = Selection.DialogResponse.None
Dim localView As View
resp = ui.SelectionManager.SelectScreenPosition("Select Screen Position", localView, location)
If resp <> Selection.DialogResponse.Back And resp <> Selection.DialogResponse.Cancel Then
Return Selection.Response.Ok
Else
Return Selection.Response.Cancel
End If

End Function

End Module

great! thanks!

is it possible to focus on a location with given x,y coordinate in drafting?

Can you be more specific on what you mean by "focus on a location"?

Is there an interactive NX command that has the desired behavior so we can see an example?

Help,
My code fails at the end when the function coordinates is called.
Thanks

if mySelObj.GetType.ToString="NXOpen.Routing.ExtractPort" then
Dim routingExtractPort as NXOpen.Routing.ExtractPort = mySelObj

Dim routingExtractPoint3D as NXOpen.Point3D
routingExtractPoint3D = routingExtractPort.Position()
lwPoint3D("routingExtractPoint3D",routingExtractPoint3D,lw)

Dim stockOffsetPoint as NXOpen.Point
stockOffsetPoint = routingExtractPort.GetStockOffsetPoint()

Dim stockOffsetPoint3D as NXOpen.Point3D
stockOffsetPoint3D = stockOffsetPoint.coordinates()

end if

Carlo Tony Daristotile

I don't know what the line:
lwPoint3D("routingExtractPoint3D",routingExtractPoint3D,lw)
does, but I don't see any obvious errors with the rest of your code.

Wrap the troublesome line in a Try block; that way you can catch an error if it occurs and get more information about it.

Try
Dim stockOffsetPoint3D as NXOpen.Point3D
stockOffsetPoint3D = stockOffsetPoint.coordinates()
Catch ex as NXException
'echo values of ex.ErrorCode and ex.Message to the listing window or a message box for more info on the error
End Try

Hi everyone, who have a journal or a grip to create a 3D XYZ coordinate chart on drawing with numbers pointing each point on view and describing them on the chart (table)?
e.g: I have a model with about 100 points on the surface in many points of the model, so I need to show each one on the drawing and their respective coordinate in a table, but selecting all points at the same time.Thanks in advance!

You might find something useful in one of the following eng-tips threads:
http://www.eng-tips.com/viewthread.cfm?qid=336107
http://www.eng-tips.com/viewthread.cfm?qid=350228

Thanks for the response, but I'm already saw this thread and thats just create a table by clicking on point by point, or selecting all points and create a note with the coordinates but I need the coordinate on the drawing with leaders and table, anyway thank you very much!

We might be able to modify one of these journals to meet your needs. What is it exactly that you need that these journals do not give you?

Hi,
I tried to run your code which gave me a NullReferenceException “object reference not set to an instance of an object” at this point:

myPt1.X = rnd1.Next(-max, max) + rnd1.NextDouble

I think it might have something to do with the framework version (4 client profile) I'm using on the visual studio 2010.
Apart from that I'm a pretty helpless. Thanks in advance for any help!
Julian

Did you remember to declare the "rnd1" variable before using it?

Dim rnd1 As New Random()

Yes, I just copied your code so I have exactly the same as in "Creating a dumb point with CreatePoint(Point3d)"
But I made the mistake of telling you the wrong line where the nullreference appears, sorry!!
It's actually right at the point where the newPt(i) object is given a value:

newPt(i) = workPart.Points.CreatePoint(myPt1)

Could maybe the way the Point Class has to be initialized be different in the .net framework I use?

In debug mode I could also observe that the elements of newPt were "nothing" instead of an instance of the Point class.

In the meantime i've been able to create this point using Snap.Create.Point. It works for know but I think it would be interesting to figure out why it didn't work before...

I see you are using VS 2010 (as am I), what version of NX are you using?

I was using NX 7.5 at the time this article was written; I verified that the journal also works in NX 8.5 and 9.

I don't think the .net framework version plays a part in the point constructor, but just in case - I have installed:

  • 2.0 sp2
  • 3.0 sp2
  • 3.5 sp1
  • 4.0
  • 4.5

I am currently using NX 8.5 and those are the .net framework versions I can chose in Visual Studio:

- 2.0
- 3.0
- 3.5
- 3.5 Client Profile
- 4.0
- 4.0 Client Profile

How confident are you in NX's overridden equals method for Point3d? Without documentation how am I to guess what kind of tolerance their using in the comparison? For example,


if closePoint1.Equals(closepoint2) Then

Compared to


If Math.Abs(closePoint1.X - closepoint2.X) < 0.001 And Math.Abs(closePoint1.Y - closepoint2.Y) < 0.001 And Math.Abs(closePoint1.Z - closepoint2.Z) < 0.001 Then

NX 8.5
NX 9.0

I'd suggest using your own comparison method so that you have full control over the tolerance used.

Since the Point3D is a structure, the .Equals method does value testing (it will check the 2 values byte for byte to see if they match). I'm confident that the .Equals method, when used on Point3D's, will only return True if the 2 structures are exactly equal.

I'm less confident about using the .Equals method on Point objects. It may be that the .Equals method only does reference testing on objects (the default behavior for the .net .Equals method); but it may be that it is overridden in the NXOpen API to test the values of the Point objects. Impossible to know without further testing.

For more information on the .net .Equals method, see:
http://msdn.microsoft.com/en-us/library/bsc2ak47

I have some 4-5 points in my drawing model..How can I know the names of the points using journal?..Like Point(4),Point(5) etc.