Click here to Skip to main content
15,884,099 members
Articles / Programming Languages / Visual Basic

Add a point to a polyline

Rate me:
Please Sign up or sign in to vote.
4.84/5 (7 votes)
18 Sep 2012CPOL4 min read 42K   2K   22  
Insert a new point to a polyline
Module Geometry
    ''' <summary>
    ''' Finds which side of a line the point is
    ''' </summary>
    ''' <param name="PointToBeEvaluated">Evaluation point</param>
    ''' <param name="StartPointOnLine">Startpoint of line</param>
    ''' <param name="EndPointOnLine">Endpoint on line</param>
    ''' <returns>-1 for a point to the right, 0 for a point on the line, +1 for a point to the left</returns>
    ''' <remarks></remarks>
    Private Function WhichSide(ByVal PointToBeEvaluated As Point, ByVal StartPointOnLine As Point, ByVal EndPointOnLine As Point) As Integer
        Dim ReturnvalueEquation As Double
        ReturnvalueEquation = ((PointToBeEvaluated.Y - StartPointOnLine.Y) _
                               * (EndPointOnLine.X - StartPointOnLine.X)) - ((EndPointOnLine.Y - StartPointOnLine.Y) _
                               * (PointToBeEvaluated.X - StartPointOnLine.X))

        If ReturnvalueEquation > 0 Then
            Return -1
        ElseIf ReturnvalueEquation = 0 Then
            Return 0
        Else
            Return 1
        End If
    End Function

    ''' <summary>
    ''' Returns the distance from a point to a line
    ''' </summary>
    ''' <param name="LinePoint1"></param>
    ''' <param name="LinePoint2"></param>
    ''' <param name="TestPoint"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function DistanceFromLine(ByVal LinePoint1 As Point, ByVal LinePoint2 As Point, TestPoint As Point) As Double
        Dim d As Double
        d = Math.Abs((LinePoint2.X - LinePoint1.X) * (LinePoint1.Y - TestPoint.Y) - (LinePoint1.X - TestPoint.X) * (LinePoint2.Y - LinePoint1.Y))
        d = d / Math.Sqrt((LinePoint2.X - LinePoint1.X) ^ 2 + (LinePoint2.Y - LinePoint1.Y) ^ 2)
        Return d
    End Function

    Private Function DistanceBetweenPoints(ByVal Point1 As Point, Point2 As Point) As Double
        Return Math.Sqrt((Point1.X - Point2.X) ^ 2 + (Point1.Y - Point2.Y) ^ 2)
    End Function

    ''' <summary>
    ''' Calculate the angel in degrees between point 1 and 3 at point 2
    ''' </summary>
    ''' <param name="Point1"></param>
    ''' <param name="Point2"></param>
    ''' <param name="Point3"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function Angles(ByVal Point1 As Point, ByVal Point2 As Point, ByVal Point3 As Point) As Double
        Dim result As Double
        Dim a, b, c As Double
        c = DistanceBetweenPoints(Point1, Point3)
        b = DistanceBetweenPoints(Point1, Point2)
        a = DistanceBetweenPoints(Point2, Point3)
        result = Math.Acos((a ^ 2 + b ^ 2 - c ^ 2) / (2 * b * a))
        Return result
    End Function

    ''' <summary>
    ''' Calculates the Normal vector at point 1
    ''' </summary>
    ''' <param name="Point1"></param>
    ''' <param name="point2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function Normal2D(ByVal Point1 As Point, ByVal point2 As Point, Optional ByVal theta As Double = Math.PI / 2) As Point
        Dim p As New Point

        p.X = Math.Cos(theta) * (point2.X - Point1.X) - Math.Sin(theta) * (point2.Y - Point1.Y) + Point1.X
        p.Y = Math.Sin(theta) * (point2.X - Point1.X) + Math.Cos(theta) * (point2.Y - Point1.Y) + Point1.Y
        Return p
    End Function


    ''' <summary>
    ''' Insert a new point to the line
    ''' </summary>
    ''' <param name="OriginalPointColletion"></param>
    ''' <param name="NewPoint"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function InsertPoint(ByVal OriginalPointColletion As PointCollection, ByVal NewPoint As Point) As PointCollection
        Dim result As New PointCollection
        result = OriginalPointColletion.Clone
        Dim min_distance As Double = Double.MaxValue
        'For Each p As Point In result
        '    min_distance += DistanceBetweenPoints(NewPoint, p)
        'Next
        Dim temp_distance As Double
        Dim index As Integer

        Dim VectorLinesCalc As New List(Of VectorLine)
        VectorLinesCalc = CalculateAllAngles(OriginalPointColletion)

        For i As Integer = 0 To OriginalPointColletion.Count - 2
            temp_distance = DistanceFromLine2(NewPoint, VectorLinesCalc(i), VectorLinesCalc(i + 1))
            If temp_distance < min_distance Then
                min_distance = temp_distance
                index = i + 1
            End If
        Next

        If DistanceBetweenPoints(OriginalPointColletion(0), NewPoint) < min_distance Then
            min_distance = DistanceBetweenPoints(OriginalPointColletion(0), NewPoint)
            index = 0
        End If

        If DistanceBetweenPoints(OriginalPointColletion(OriginalPointColletion.Count - 1), NewPoint) < min_distance Then
            index = -1
            min_distance = DistanceBetweenPoints(OriginalPointColletion(OriginalPointColletion.Count - 1), NewPoint)
        End If

        If Not index = -1 Then
            result.Insert(index, NewPoint)
        Else
            result.Add(NewPoint)
        End If
        Return result
    End Function

    Private Function DistanceFromLine2(TestPoint As Point, ByVal vector1 As VectorLine, ByVal vector2 As VectorLine) As Double

        Dim FirstTest, SecondTest As Integer

        FirstTest = WhichSide(TestPoint, vector1.Point1, vector1.Point2)
        SecondTest = WhichSide(TestPoint, vector2.Point1, vector2.Point2)

        If FirstTest <> SecondTest Then
            Return DistanceFromLine(vector1.Point1, vector2.Point1, TestPoint)
        Else
            Return Double.MaxValue
        End If

    End Function


    Public Function CalculateAllAngles(ByVal OriginalPointCollection As PointCollection) As List(Of VectorLine)
        Dim result As New List(Of VectorLine)
        For i As Integer = 0 To OriginalPointCollection.Count - 1
            Dim NewVectorLine As New VectorLine
            If i = 0 Then
                NewVectorLine.Point2 = Normal2D(OriginalPointCollection(i), OriginalPointCollection(i + 1))
                NewVectorLine.Point1 = OriginalPointCollection(i)
                result.Add(NewVectorLine)
            ElseIf i = OriginalPointCollection.Count - 1 Then
                NewVectorLine.Point2 = Normal2D(OriginalPointCollection(i), OriginalPointCollection(i - 1), 3 * Math.PI / 2)
                NewVectorLine.Point1 = OriginalPointCollection(i)
                result.Add(NewVectorLine)
            Else
                NewVectorLine.Point1 = OriginalPointCollection(i)
                Dim angl As Double = Angles(OriginalPointCollection(i - 1), OriginalPointCollection(i), OriginalPointCollection(i + 1))

                Dim PreviousAngle, NextAngle As Integer
                PreviousAngle = WhichSide(result(i - 1).Point2, OriginalPointCollection(i - 1), OriginalPointCollection(i))
                NextAngle = WhichSide(OriginalPointCollection(i + 1), OriginalPointCollection(i - 1), OriginalPointCollection(i))
                If PreviousAngle = NextAngle Then
                    NewVectorLine.Point2 = Normal2D(OriginalPointCollection(i), OriginalPointCollection(i + 1), angl / 2)
                Else
                    NewVectorLine.Point2 = Normal2D(OriginalPointCollection(i), OriginalPointCollection(i + 1), (2 * Math.PI - angl) / 2)
                End If
                result.Add(NewVectorLine)
            End If
        Next
        Return result
    End Function


    Public Class VectorLine
        Public Point1 As New Point
        Public Point2 As New Point
    End Class
End Module

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer
Norway Norway
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions