Results 1 to 10 of 10

Thread: Sorting a List (Of Point) Based on Distance

  1. #1

    Thread Starter
    Hyperactive Member neef's Avatar
    Join Date
    Dec 2001
    Location
    Boston
    Posts
    311

    Sorting a List (Of Point) Based on Distance

    This is a nice little puzzle challenge.

    I have a list of collection of points on the screen. I want to order them based on their distance from a seperate, independent point. What's working is I have a function GetDistance which does the dirty pythagorian work of returning the distance between two points.

    Let me explain more in the code block below...

    Code:
    'Create the set point from which to start all measurements from (startpoint)
    dim SetPoint as new Point(200,200)
    'Create a list to hold arbitrary points to test (endpoints)
    dim ListOfPoints as new list(of point)
    'Add points to test
    ListOfPoints.Add(1000,2000)
    ListOfPoints.Add(340,400)
    ListOfPoints.Add(1022,53)
    ListOfPoints.Add(333,987)
    
    'The code should now rearrange the above list from closest to furthest from 
    'the SetPoint using my GetDistance(StartPoint, EndPoint) pythagorian function
    Thanks for any help in advance.
    Intermediate Level Programmer Extraordinaire

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Sorting a List (Of Point) Based on Distance

    You could probably create a custom sorter, but it could end up being kind of painful. After all, it would require that the distance be calculated for every comparison, of which there will be many for a sort. Therefore, you are going to end up doing far more distance calculations than the number of items in the list. So is that worthwhile? If it isn't, then you might want to create a new class that holds a point and a distance, then sort that list rather than sorting the point list. By doing this, you can make the distance a member of the class and only calculate it once per point, rather than twice per comparison.
    My usual boring signature: Nothing

  3. #3

    Thread Starter
    Hyperactive Member neef's Avatar
    Join Date
    Dec 2001
    Location
    Boston
    Posts
    311

    Re: Sorting a List (Of Point) Based on Distance

    That's the outside the box thinking I was looking for, thank you.

    How would you use the Sort method in this case (using a member variable of an object to sort the objects themselves)?

    Sort has always thrown me off a little; I'm not sure why.
    Intermediate Level Programmer Extraordinaire

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Sorting a List (Of Point) Based on Distance

    You just need to implement IComparable on the class. That will create a stub of CompareTo. What you do in there is something I always forget, so I go to MSDN where there happens to be a good example, which I copy into my project. Here's what is in MSDN:
    Code:
    Public Overloads Function CompareTo(ByVal obj As Object) As Integer _
            Implements IComparable.CompareTo
    
            If TypeOf obj Is Temperature Then
                Dim otherTemperature As Temperature = DirectCast(obj, Temperature)
                Return Me.temperatureF.CompareTo(otherTemperature.temperatureF)
            Else
               Throw New ArgumentException("object is not a Temperature")
            End If   
        End Function
    I believe that there is also an IComparable (of T), which would be better, as you would use your class for T, and instead of receiving an object, you will get an argument of type T, so that whole If statement and the cast can be removed. You just want to compare the distance of the incoming T to the distance of the current instance, and return 1 or -1 depending on which should sort ahead of the other.

    I never remember how it works, though, so I happen to know that MSDN spells it out.
    My usual boring signature: Nothing

  5. #5
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,415

    Re: Sorting a List (Of Point) Based on Distance

    Quote Originally Posted by Shaggy Hiker View Post
    I believe that there is also an IComparable (of T), which would be better.
    Shaggy is right...

    vb Code:
    1. Public Class Class1
    2.     Implements IComparable(Of Class1)
    3.  
    4.     Public Function CompareTo(ByVal other As Class1) As Integer Implements System.IComparable(Of Class1).CompareTo
    5.         Return Me.temperatureF.CompareTo(other.temperatureF)
    6.     End Function
    7.  
    8.     Private _temperatureF As Decimal
    9.     Public Property temperatureF As Decimal
    10.         Get
    11.             Return _temperatureF
    12.         End Get
    13.         Set(ByVal value As Decimal)
    14.             _temperatureF = value
    15.         End Set
    16.     End Property
    17.  
    18. End Class

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Sorting a List (Of Point) Based on Distance

    You can implement IComparable on the item type but that doesn't necessarily make sense in all cases, plus it's downright impossible if you're using a type that you didn't define yourself. In your case, it would make most sense to either define a class that implements IComparer (note that this is different to IComparable) or else just write a method that matched the signature of the Comparison delegate. Follow the Blog link in my signature and check out my three-part post on sorting lists for all the details.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  7. #7

    Thread Starter
    Hyperactive Member neef's Avatar
    Join Date
    Dec 2001
    Location
    Boston
    Posts
    311

    Re: Sorting a List (Of Point) Based on Distance

    Thank you all for your help.
    Intermediate Level Programmer Extraordinaire

  8. #8
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,415

    Re: Sorting a List (Of Point) Based on Distance

    could you post your GetDistance function?

  9. #9
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,415

    Re: Sorting a List (Of Point) Based on Distance

    try this:

    vb Code:
    1. 'Create a list to hold arbitrary points to test (endpoints)
    2. Dim ListOfPoints As New List(Of Point)
    3. 'Add points to test
    4. ListOfPoints.Add(New Point(1000, 2000))
    5. ListOfPoints.Add(New Point(340, 400))
    6. ListOfPoints.Add(New Point(1022, 53))
    7. ListOfPoints.Add(New Point(333, 987))
    8.  
    9. ListOfPoints.Sort(New comparer2)

    this is the comparer:

    vb Code:
    1. Public Class comparer2
    2.     Implements IComparer(Of Point)
    3.  
    4.     Public Function Compare(ByVal x As Point, ByVal y As Point) As Integer Implements System.Collections.Generic.IComparer(Of Point).Compare
    5.         'Create the set point from which to start all measurements from (startpoint)
    6.         Dim SetPoint As New Point(200, 200)
    7.         Return lineLength(SetPoint, x).CompareTo(lineLength(SetPoint, y))
    8.     End Function
    9.  
    10.     ''' <summary>
    11.     ''' lineLength
    12.     ''' </summary>
    13.     ''' <param name="p1">point1</param>
    14.     ''' <param name="p2">point2</param>
    15.     ''' <returns>length in pixels between p1 and p2</returns>
    16.     ''' <remarks></remarks>
    17.     Public Shared Function lineLength(ByVal p1 As Point, ByVal p2 As Point) As Double
    18.         Dim r As Rectangle = normalizeRect(p1, p2)
    19.         Return Math.Sqrt(r.Width ^ 2 + r.Height ^ 2)
    20.     End Function
    21.  
    22.     ''' <summary>
    23.     ''' </summary>
    24.     ''' <param name="p1">point1</param>
    25.     ''' <param name="p2">point2</param>
    26.     ''' <returns>a rectangle encapsulating p1, p2</returns>
    27.     ''' <remarks></remarks>
    28.     Private Shared Function normalizeRect(ByVal p1 As Point, ByVal p2 As Point) As Rectangle
    29.         Dim r As New Rectangle
    30.         If p1.X < p2.X Then
    31.             r.X = p1.X
    32.             r.Width = p2.X - p1.X
    33.         Else
    34.             r.X = p2.X
    35.             r.Width = p1.X - p2.X
    36.         End If
    37.         If p1.Y < p2.Y Then
    38.             r.Y = p1.Y
    39.             r.Height = p2.Y - p1.Y
    40.         Else
    41.             r.Y = p2.Y
    42.             r.Height = p1.Y - p2.Y
    43.         End If
    44.         Return r
    45.     End Function
    46.  
    47. End Class

  10. #10
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Sorting a List (Of Point) Based on Distance

    Just to be clear, here's an example of an IComparer that would suit your situation:
    vb.net Code:
    1. Friend Class PointComparer
    2.     Implements IComparer(Of Point)
    3.  
    4.     Private reference As Point
    5.  
    6.  
    7.     Public Sub New()
    8.         'Use the origin as the default reference point.
    9.         Me.New(Point.Empty)
    10.     End Sub
    11.  
    12.     Public Sub New(ByVal reference As Point)
    13.         Me.reference = reference
    14.     End Sub
    15.  
    16.  
    17.     Public Function Compare(ByVal pt1 As Point, _
    18.                             ByVal pt2 As Point) As Integer Implements IComparer(Of Point).Compare
    19.         Dim distance1 As Double = Math.Sqrt((pt1.X - Me.reference.X) ^ 2 + (pt1.Y - Me.reference.Y) ^ 2)
    20.         Dim distance2 As Double = Math.Sqrt((pt2.X - Me.reference.X) ^ 2 + (pt2.Y - Me.reference.Y) ^ 2)
    21.  
    22.         Return distance1.CompareTo(distance2)
    23.     End Function
    24.  
    25. End Class
    And here's how you might use it:
    vb.net Code:
    1. Private Sub SortPointsByDistanceFromReference(ByVal points As List(Of Point), _
    2.                                               ByVal reference As Point)
    3.     points.Sort(New PointComparer(reference))
    4. End Sub
    Note that, as with all sorting, it still makes use of the IComparable interface. In the PointComparer.Compare method the IComparable.CompareTo implementation of the Double structure is being invoked to compare two Double values that represent the distances of the two Points from the specified reference Point.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width