Submitted by JXB on Wed, 06/10/2015 - 04:41
Forums:
To all
I do not believe NX.CAE has an option to warn user if points (or MeshPoints) already exist at a given position in one tries creating a new one (at the same position). I am therefore thinking about a “small” program which could loop through all the points selected (and/or Meshpoints), warn user of duplicate exist and delete if requested (?)
Possible scope is
Select a list of points (or Meshpoints)
Check if duplicate points exist at a given position
Delete duplicate points (to keep only 1)
Does anyone have any good idea/suggestions, etc on the best way to start?
Thanks
Regards
JXB
re: duplicate mesh points
I'd suggest sorting the list of points by one of the coordinates, let's say the X coordinate, for example; then you can loop through the list looking for duplicates. If the X coordinate matches, continue checking on the Y and Z coordinates. If it is a match, add it to a list of duplicates (these will be deleted later). If it isn't a match, move along to the next point in the list.
The code below illustrates this strategy. The journal will create point objects, run the code in a new file (or use the undo function to get rid of them later). The subroutine "RemoveDuplicatePoints" is the area to focus on, the rest is mostly setup and output.
Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Module Module1
Dim theSession As Session = Session.GetSession()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim lw As ListingWindow = theSession.ListingWindow
Sub Main()
If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If
Dim workPart As Part = theSession.Parts.Work
lw.Open()
Const undoMarkName As String = "remove duplicates"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, undoMarkName)
Dim pointList As New List(Of Point)
InitializePoints(pointList, 10, 3)
lw.WriteLine("original list of points")
For Each pt As Point In pointList
lw.WriteLine(pt.Coordinates.ToString)
Next
lw.WriteLine("")
RemoveDuplicatePoints(pointList)
lw.WriteLine("duplicates removed, count: " & pointList.Count.ToString)
lw.WriteLine("list of points with duplicates removed")
For Each pt As Point In pointList
lw.WriteLine(pt.Coordinates.ToString)
Next
lw.Close()
End Sub
Sub InitializePoints(ByRef ptList As List(Of Point), ByVal numPts As Integer, ByVal numDuplicates As Integer)
Dim rnd1 As New Random()
Dim max As Integer
If theSession.Parts.Work.PartUnits = Part.Units.Inches Then
max = 10
Else 'metric file
max = 250
End If
Dim myPt1 As New Point3d(0, 0, 0)
'create random points
For i As Integer = 0 To numPts - 1
myPt1.X = rnd1.Next(-max, max) + rnd1.NextDouble
myPt1.Y = rnd1.Next(-max, max) + rnd1.NextDouble
myPt1.Z = rnd1.Next(-max, max) + rnd1.NextDouble
Dim newPt As Point
newPt = theSession.Parts.Work.Points.CreatePoint(myPt1)
newPt.SetVisibility(SmartObject.VisibilityOption.Visible)
ptList.Add(newPt)
Next
'create duplicate points
'duplicate the first n points at random locations in the list
Dim locations As New List(Of Integer)
For i As Integer = 0 To numDuplicates - 1
lw.WriteLine("i = " & i.ToString)
Dim loc As Integer
Do
loc = rnd1.Next(numDuplicates, ptList.Count - 1)
'lw.WriteLine("loc = " & loc.ToString)
'lw.WriteLine("locations.Contains(loc) = " & locations.Contains(loc).ToString)
Loop Until Not locations.Contains(loc)
locations.Add(loc)
ptList.Item(loc).SetCoordinates(ptList.Item(i).Coordinates)
ptList.Item(loc).RedisplayObject()
Next
End Sub
Function SortPointsX(ByVal x As Point, ByVal y As Point) As Integer
If x.Coordinates.X > y.Coordinates.X Then
Return 1
End If
If x.Coordinates.X < y.Coordinates.X Then
Return -1
End If
If x.Coordinates.X = y.Coordinates.X Then
Return 0
End If
End Function
Sub RemoveDuplicatePoints(ByRef ptList As List(Of Point))
Dim ptDelete As New List(Of Point)
ptList.Sort(AddressOf SortPointsX)
lw.WriteLine("sorted list of points")
For Each temp As Point In ptList
lw.WriteLine(temp.Coordinates.ToString)
Next
lw.WriteLine("")
Dim myModelingTolerance As Double
theUfSession.Modl.AskDistanceTolerance(myModelingTolerance)
For i As Integer = 0 To ptList.Count - 2
For j As Integer = i + 1 To ptList.Count - 1
Dim xDiff As Double = Math.Abs(ptList.Item(i).Coordinates.X - ptList.Item(j).Coordinates.X)
Dim yDiff As Double = Math.Abs(ptList.Item(i).Coordinates.Y - ptList.Item(j).Coordinates.Y)
Dim zdiff As Double = Math.Abs(ptList.Item(i).Coordinates.Z - ptList.Item(j).Coordinates.Z)
lw.WriteLine("point 'i = " & i.ToString & "': " & ptList.Item(i).Coordinates.ToString)
lw.WriteLine("point 'j = " & j.ToString & "': " & ptList.Item(j).Coordinates.ToString)
lw.WriteLine("xDiff: " & xDiff.ToString)
lw.WriteLine("yDiff: " & yDiff.ToString)
lw.WriteLine("zDiff: " & zdiff.ToString)
If xDiff <= myModelingTolerance Then
lw.WriteLine("X coordinates are within tolerance")
'possible match, keep checking
If yDiff <= myModelingTolerance Then
lw.WriteLine("Y coordinates are within tolerance")
'possible match, check on Z coordinate
If zdiff <= myModelingTolerance Then
'it is a duplicate, remove it from the list
lw.WriteLine("Z coordinates are within tolerance, this is a duplicate")
lw.WriteLine("adding point to the delete list, continue checking with next 'j' point")
lw.WriteLine("")
'add the point to the delete list if it is not already there
If Not ptDelete.Contains(ptList.Item(i)) Then
ptDelete.Add(ptList.Item(i))
End If
Else
Continue For
End If
Else
lw.WriteLine("Y coordinates NOT within tolerance, skipping to next 'j' point")
lw.WriteLine("")
'Y coordinate is not a match, skip to next "j" point
Continue For
End If
Else
lw.WriteLine("X coordinates NOT witin tolerance, skipping to next 'i' point")
lw.WriteLine("")
'X coordinate is not a match, skip to next "i" point
'no other point in the list is a possible match because the list is sorted
'the rest of the "j" points will be getting farther away from the "i" point
Exit For
End If
Next
Next
For Each temp As Point In ptDelete
ptList.Remove(temp)
Next
'delete any duplicate points found
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "Delete duplicate points")
theSession.UpdateManager.ClearErrorList()
Dim nErrs1 As Integer
nErrs1 = theSession.UpdateManager.AddToDeleteList(ptDelete.ToArray)
Dim nErrs2 As Integer
nErrs2 = theSession.UpdateManager.DoUpdate(markId1)
End Sub
Public Function GetUnloadOption(ByVal dummy As String) As Integer
'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
End Function
End Module
re: duplicate mesh points
You must have had something on the side ready surely!!! I have only managed to code the "select the points" (I found the function in another discussion) and
If SelectPoints("Select points", thePoints) = Selection.Response.Cancel Then
Return
End If
For Each thepoint as Point In thePoints
'get co-ordinate
lw.WriteLine("thePoint.GetType.ToString = " & thePoint.GetType.ToString)
lw.WriteLine("coordinates: " & thePoint.Coordinates.ToString)
lw.WriteLine("")
Next thepoint
after that I had to go back to work!
I have just printed a copy of the kindly provided example and will go through at leisure tonight. A fair bit for my small brain to take
Thanks
Regards
re: find duplicates
It is very similar to code in the "find duplicate sheet bodies" journal. I had some help from FrankSwinks on that one; he suggested the method for searching through the items.
Also, I made a very small change in the code posted above. In the RemoveDuplicatePoints sub, I changed this:
ptDelete.Add(ptList.Item(i))
to this:
If Not ptDelete.Contains(ptList.Item(i)) Then
ptDelete.Add(ptList.Item(i))
End If
That way the duplicates will only be added to the 'delete' list once. This can be important for 'real world' use.
RE: find duplicates - added option
Thanks for that NXjournaling. Added a couple of things to use the code in the "real" world.
1. Will be looking at adding an option to add the duplicated point to a group. Hoping to do that in a fem part.
2. added a function to select the points.
2.1. No "pretty" as in the Main() I then loop to allocate each member of the array (returned by the select function) to the List (of Point). I need to find a way of returning a List directly
2.2. Also need to look at a way of selecting either Point or Mesh Point (which obviously only works in a FEM part!) Thinking of a question to the user (Do you want Point or MeshPoint? if part =FEM Else just Point) which could be used to set the selectionMask_array(0)
Regards
JXB
Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Module Module1
Dim theSession As Session = Session.GetSession()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim theUISession As UI = UI.GetUI
Dim lw As ListingWindow = theSession.ListingWindow
#Region "Main"
Sub Main()
Dim theSelectedPoints() As NXObject
Dim pointList As New List(Of Point)
If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If
Dim workPart As Part = theSession.Parts.Work
lw.Open()
If SelectPoints("Select points", theSelectedPoints) = Selection.Response.Cancel Then
Return
End If
Dim N as Integer = Ubound(theSelectedPoints)
If N = -1 Then
lw.Writeline("No points selected - Terminating")
Return
Else
lw.Writeline("Number of points selected: " & N.ToString)
lw.Writeline("")
For Each pt as Point In theSelectedPoints
pointList.Add(pt)
REM lw.WriteLine("coordinates: " & pt.Coordinates.ToString)
Next pt
End if
'Ask user if duplicate points should be deleted
Dim answer As Integer
dim bDeleteDuplicatePt As Boolean
'Answer = 1 = Yes Answer = 2 = No Otherwise the returned value will be -2
answer = theUISession.NXMessageBox.Show("Delete Points", _
NXMessageBox.DialogType.Question, _
"Delete duplicate point(s) if found?")
If answer = 1 Then
bDeleteDuplicatePt = True
Else
bDeleteDuplicatePt=False
lw.WriteLine("Duplicate points will not be deleted but added to group 'Duplicate Points' instead")
End if
'Check for duplicate
RemoveDuplicatePoints(pointList,bDeleteDuplicatePt)
End Sub
#End Region
#Region "Select Points"
Function SelectPoints(ByVal prompt As String, byRef selObj() As NXObject) As Selection.Response
Dim theUI As UI = UI.GetUI
Dim title As String = "Select points to check for duplication"
Dim includeFeatures As Boolean = False
Dim keepHighlighted As Boolean = False
Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
Dim scope As Selection.SelectionScope = Selection.SelectionScope.WorkPart
Dim selectionMask_array(0) As Selection.MaskTriple
With selectionMask_array(0)
.Type = UFConstants.UF_point_type
.Subtype = UFConstants.UF_point_subtype
End With
Dim resp As Selection.Response = theUI.SelectionManager.SelectObjects(prompt, title, scope, selAction, _
includeFeatures, keepHighlighted, _
selectionMask_array, selobj)
If resp = Selection.Response.Ok Then
Return Selection.Response.Ok
Else
Return Selection.Response.Cancel
End If
End Function
#End Region
#Region "RemoveDuplicatePoints()"
Sub RemoveDuplicatePoints(ByRef ptList As List(Of Point),bDeletePt As Boolean)
Dim iduplicatefound As Integer = 0
Dim ptDelete As New List(Of Point)
ptList.Sort(AddressOf SortPointsX)
REM lw.WriteLine("sorted list of points")
REM For Each temp As Point In ptList
REM lw.WriteLine(temp.Coordinates.ToString)
REM Next
REM lw.WriteLine("")
Dim myModelingTolerance As Double
theUfSession.Modl.AskDistanceTolerance(myModelingTolerance)
For i As Integer = 0 To ptList.Count - 2
For j As Integer = i + 1 To ptList.Count - 1
Dim xDiff As Double = Math.Abs(ptList.Item(i).Coordinates.X - ptList.Item(j).Coordinates.X)
Dim yDiff As Double = Math.Abs(ptList.Item(i).Coordinates.Y - ptList.Item(j).Coordinates.Y)
Dim zdiff As Double = Math.Abs(ptList.Item(i).Coordinates.Z - ptList.Item(j).Coordinates.Z)
REM lw.WriteLine("point 'i = " & i.ToString & "': " & ptList.Item(i).Coordinates.ToString)
REM lw.WriteLine("point 'j = " & j.ToString & "': " & ptList.Item(j).Coordinates.ToString)
REM lw.WriteLine("xDiff: " & xDiff.ToString)
REM lw.WriteLine("yDiff: " & yDiff.ToString)
REM lw.WriteLine("zDiff: " & zdiff.ToString)
If xDiff <= myModelingTolerance Then
'lw.WriteLine("X coordinates are within tolerance")
'possible match, keep checking
If yDiff <= myModelingTolerance Then
'lw.WriteLine("Y coordinates are within tolerance")
'possible match, check on Z coordinate
If zdiff <= myModelingTolerance Then
'it is a duplicate, remove it from the list
'lw.writeline("duplicate point found")
iduplicatefound +=1
'lw.WriteLine("Z coordinates are within tolerance, this is a duplicate")
'lw.WriteLine("adding point to the delete list, continue checking with next 'j' point")
'lw.WriteLine("")
If Not ptDelete.Contains(ptList.Item(i)) Then
ptDelete.Add(ptList.Item(i))
End If
Else
Continue For
End If
Else
'lw.WriteLine("Y coordinates NOT within tolerance, skipping to next 'j' point")
'lw.WriteLine("")
'Y coordinate is not a match, skip to next "j" point
Continue For
End If
Else
'lw.WriteLine("X coordinates NOT within tolerance, skipping to next 'i' point")
'lw.WriteLine("")
'X coordinate is not a match, skip to next "i" point
'no other point in the list is a possible match because the list is sorted
'the rest of the "j" points will be getting farther away from the "i" point
Exit For
End If
Next
Next
if iduplicatefound <> 0 Then
lw.writeline("Total duplicate point found: " & iduplicatefound.ToString)
Else
lw.writeline("No duplicate point found")
End if
If bDeletePt = True And iduplicatefound <> 0 Then
For Each temp As Point In ptDelete
ptList.Remove(temp)
Next
'delete any duplicate points found
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "Delete duplicate points")
theSession.UpdateManager.ClearErrorList()
Dim nErrs1 As Integer
nErrs1 = theSession.UpdateManager.AddToDeleteList(ptDelete.ToArray)
Dim nErrs2 As Integer
nErrs2 = theSession.UpdateManager.DoUpdate(markId1)
Else 'Add to group
'to be added
End if
End Sub
#End Region
#Region "sort"
Function SortPointsX(ByVal x As Point, ByVal y As Point) As Integer
If x.Coordinates.X > y.Coordinates.X Then
Return 1
End If
If x.Coordinates.X < y.Coordinates.X Then
Return -1
End If
If x.Coordinates.X = y.Coordinates.X Then
Return 0
End If
End Function
#End Region
#Region "Init"
Sub InitializePoints(ByRef ptList As List(Of Point), ByVal numPts As Integer, ByVal numDuplicates As Integer)
Dim rnd1 As New Random()
Dim max As Integer
If theSession.Parts.Work.PartUnits = Part.Units.Inches Then
max = 10
Else 'metric file
max = 250
End If
Dim myPt1 As New Point3d(0, 0, 0)
'create random points
For i As Integer = 0 To numPts - 1
myPt1.X = rnd1.Next(-max, max) + rnd1.NextDouble
myPt1.Y = rnd1.Next(-max, max) + rnd1.NextDouble
myPt1.Z = rnd1.Next(-max, max) + rnd1.NextDouble
Dim newPt As Point
newPt = theSession.Parts.Work.Points.CreatePoint(myPt1)
newPt.SetVisibility(SmartObject.VisibilityOption.Visible)
ptList.Add(newPt)
Next
'create duplicate points
'duplicate the first n points at random locations in the list
Dim locations As New List(Of Integer)
For i As Integer = 0 To numDuplicates - 1
lw.WriteLine("i = " & i.ToString)
Dim loc As Integer
Do
loc = rnd1.Next(numDuplicates, ptList.Count - 1)
'lw.WriteLine("loc = " & loc.ToString)
'lw.WriteLine("locations.Contains(loc) = " & locations.Contains(loc).ToString)
Loop Until Not locations.Contains(loc)
locations.Add(loc)
ptList.Item(loc).SetCoordinates(ptList.Item(i).Coordinates)
ptList.Item(loc).RedisplayObject()
Next
End Sub
#End Region
#Region "unloadoption"
Public Function GetUnloadOption(ByVal dummy As String) As Integer
'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
End Function
#End Region
End Module
Thanks
Regards
RE: find duplicates - added option
Thinking about it I wonder if it would be better to remove the "Select Points" option and let the programme check all the points in the (displayed) part
Thanks
Regards
Organization and optimization
> would be better to remove the "Select Points" option and let
> the programme check all the points in the (displayed) part
Good software engineering principles tell us that selection and unduplication are two indepenedent things, so they should be two separate functions. So, there should be:
(1) A function that removes duplicates from a given list of points
(2) A function that asks the user to select points, and returns a list of the selected points.
Then, you can combine #1 and #2 in any way you like, or you can use them independently.
When you write this sort of algorithm, you have to be careful to avoid so-called "n-squared" behaviour. If you have n points, and you compare each one with each other one, than that's (roughly) n*n comparisons. If n is large, you're in big trouble.
I'd recommend that you first sort the points by distance to the origin. Then, any identical ones will end up adjacent to each other in the sorted list, and will be easy to identify. Sorting is an n*log(n) process, which is a lot better than n*n for large n. You can use the standard .NET sorting function. http://www.codeproject.com/Tips/323985/Sorting-using-Csharp-Lists
RE: Organization and optimization
Thanks ciao for the reminders. A I am not a software engineer so I dispense myself with the good practise of this field. Just kidding. Always happy to learn good/standard practise even if I am just a "Sunday" programmer.
I was vaguely aware that having a very large numbers of Point to process may take some time (didn't know it was "called n-squared" behaviour though). As the programme is tailored to me need I do not think I will ever have more than a couple of hundred but I get your point. I had in mind of doing a few timing tests.
I have taken on board your suggestion about keeping the functions separate and thinking alone the following lines
user selection of all the points to be checked
SelectionPoint()
checkifduplicate(ptselected)
If checkifduplicate(ptselected).count <> 0 And userchoice=True Then deleteduplicate()
Need to go through the detail as the function checkifduplicate() should returns a List() but I would like it to deal with Point and MeshPoint. Can one have in input something like
Sub CheckIfDuplicate(ptListSelected As List(Of NXObject) As List (Of NxObject)
On the use of SelectionManager
theUI.SelectionManager.SelectObjects
I see that on the interface displayed to the user when the function is called that the option 'Select All' is available. Is there a way of calling this function and "forcing" the selection to 'select all'?
on MeshPoint
I have gone through the file uf_object_types.h to find the type and subtype for a meshpoint to be used in the selection.MaskTriple but there was not subtype defined. Does this make sense?
Thanks
Regards
JXB
Thanks
Regards
re: no subtype
If there are no subtypes defined for the given type, use the subtype value of 0 (zero) or UF_all_subtype (value -1). Either should work.
If subtypes are defined in later versions of NX, you'll need to update your code accordingly.
RE: no subtype - use of UF_all_subtype
thanks. Looks like the filter is working
Dim answer As String = ""
Dim iuserchoice As Integer
Do
answer = NXInputBox.GetInputString("Point Selection", "Point or MeshPoint to be selected? 1=Point, 2=MeshPoint", "1")
'if cancel is pressed, exit sub
If answer = "" Then Exit Sub
Loop Until Integer.TryParse(answer, iuserchoice)
Select Case iuserchoice
Case 1
With selectionMask_array(0)
.Type = UFConstants.UF_point_type
.Subtype = UFConstants.UF_point_subtype
End With
Case 2
With selectionMask_array(0)
.Type = UFConstants.UF_meshpoint_type
.Subtype = UFConstants.UF_all_subtype
End With
End Select
Thanks
Regards