Line Geometry

Line segment

A line segment is a part of line bounded by two distinct end points. Dealing with line segment is fundamental in geometry and I have dedicated the below topics and codes to various operation performed with a line segment and other general geometric shapes.

A line segment is stored with two end points. In VB.Net, C#.Net the points in a Panel or picture box where a line can be displayed uses integer variable. Also the positive x coordinate is from left to right and positive y coordinate is from top to bottom. I have used to positive y coordinate as from bottom to top. So my code strategy for storing a point is as below

Store point with Actual coordinate (depends on scale , mid point (can be used for pan the points around)

Const MidPtX As Integer = 300
    Const MidPtY As Integer = 300
    Const ScaleXY As Integer = 25
    Shared _AllPts As List(Of Point_Holder)
    
    Public Class Point_Holder
        Dim X_loc As Double
        Dim Y_Loc As Double
        Public ReadOnly Property xLocation() As Double
            Get
                Return X_loc
            End Get
        End Property
        Public ReadOnly Property yLocation() As Double
            Get
                Return Y_Loc
            End Get
        End Property
        Public ReadOnly Property Sc_X() As Integer
            Get
                Return (CInt(X_loc * ScaleXY) + MidPtX)
            End Get
        End Property
        Public ReadOnly Property Sc_Y() As Integer
            Get
                Return (MidPtY - CInt(Y_Loc * ScaleXY))
            End Get
        End Property
        Public Sub Set_Points1(ByVal t_X As Double, ByVal t_Y As Double)
            X_loc = t_X
            Y_Loc = t_Y
        End Sub
        Public Sub Set_Points2(ByVal s_X As Integer, ByVal s_Y As Integer)
            X_loc = (s_X -  MidPtX)/ScaleXY
            Y_Loc =(MidPtY - s_Y)/ScaleXY
        End Sub
    End Class

Now X_loc & Y_loc has actual coordinates, where Sc_X & Sc_Y screen coordinates. We just need the identity of two nodes to define a line and any common geometrical with just identity of the points.

Intersection of two lines

Let the the two lines be AB & CD

AB: A(1-t) + Bt & CD: C(1-s) + Dt where 0<t<1 & 0<s<1

if these two lines intersect, then

Ax + t(Bx-Ax) = Cx + s(Dx-Cx)

Ay + t(By-Ay) = Cy + s(Dy-Cy)

we can simplify and solve for t & s. If the value t & s lies between 0 & 1 then interection occurs within the segment.

(Bx-Ax)t + (Cx-Dx)s = (Cx-Ax)

(By-Ay)t + (Cy-Dy)s = (Cy-Ay)

The code implementation is below (for solving the above equation for t & s

 Private Shared Sub twoD_Linear_Solver(ByVal a1 As Double, ByVal b1 As Double, ByVal c1 As Double, _
                                   ByVal a2 As Double, ByVal b2 As Double, ByVal c2 As Double, _
                                   ByRef t As Double, ByRef s As Double)
       
        If (a1 * b2) - (a2 * b1) = 0 Then '---- Determinant
            '---- No Solution
            t = 100000
            s = 100000
        Else
            t = ((c1 * b2) - (b1 * c2)) / ((a1 * b2) - (b1 * a2))
            s = ((a1 * c2) - (c1 * a2)) / ((a1 * b2) - (b1 * a2))
        End If
    End Sub

[||Pic: twoP1||]

[||Pic: twoP2||]

[||Pic: twoP3||]

Point in Line (Normal Distance from a point)

In VB, mouse click location is given as screen coordinates in integer format. The strategy we can use to select a line (after we know the click location) is

  • find the normal equation of the line
  • find the normal distance between the line and the click point
  • if the normal distance is less than some limit we can select the index of line.

Change the parametric equation of line (A(1-t)+B(t)) to the form ax+by+c=0

y – y1 = m (x – x1)

whereas m = (y2-y1) / (x2-x1)

simplification it becomes ax+by+c = 0

a= y2-y1

b= x1-x2

c= (y1-y2)x1 + (x2-x1)y1

Equation of perpendicular line is of the form

bx – ay = D

we know 1st point in the perpendicular line which is our click point (say x0,y0)

so D = bx0 - ay0

Now, we have perpendicular line bx – ay – D = 0 through our click point

Find one more point along this perpendicular line xs = x0+100 => ys = (b(xs) – D)/a if a<>0 otherwise vertical ray xs = x0 and ys = y0 +100

Now we have a line AB (x1,y1) -> (x2,y2) and a line perpendicular to AB which is CD (x0,y0) -> (xs,ys)

we find the intersection point of these two lines (Ix,Iy) and check whether the intersection lies between the line segment. Now if the distance formed by (Ix,Iy) and (x0,y0) are within a limit then the line is selected.

Public Class Line_Holder
        Dim _Spt As New Integer
        Dim _Ept As New Integer
        Public ReadOnly Property Spt() As Integer
            Get
                Return _Spt
            End Get
        End Property
        Public ReadOnly Property Ept() As Integer
            Get
                Return _Ept
            End Get
        End Property
        Public Sub Set_Line(ByVal Ac_S As Integer, _
                            ByVal Ac_E As Integer)
            _Spt = Ac_S '--- save only the index number of allPts
            _Ept = Ac_E '--- save only the index number of allPts
        End Sub
        Public Sub Normal_Dist_From_Point(ByRef t_AllPts As List(Of Point_Holder), ByRef SClick_X As Integer, ByRef SClick_Y As Integer)
            '--- convert the screen coordinate of the click point to actual points
            Dim AClick_X, AClick_Y As Double
            AClick_X = (SClick_X - MidPtX) / ScaleXY
            AClick_Y = (MidPtY - SClick_Y) / ScaleXY
            '---- Equation of the line ax + by + c = 0
            Dim a, b, c As Double
            a = t_AllPts(_Ept).yLocation - t_AllPts(_Spt).yLocation  'y2-y1
            b = t_AllPts(_Spt).xLocation - t_AllPts(_Ept).xLocation  'x1-x2
            c = 0 '-- no need c
            '---- Perpendicular line form bx - ay = D
            Dim D As Double
            D = b * AClick_X - a * AClick_Y
            '--- find some point at xs = x0 +100 (if a<> 0)
            Dim xs, ys As Double
            If a = 0 Then '--- vertical line
                xs = AClick_X
                ys = AClick_Y + 100
            Else
                xs = AClick_X + 100
                ys = (b * xs - D) / a
            End If
            'Now we have a perpendicular line with 2 points (AClickX,AClickY) & (xs,ys)
            Dim BxAx, DxCx, CxAx As Double
            Dim ByAy, DyCy, CyAy As Double
            Dim t, s As Double
            '------ Line Points
            BxAx = t_AllPts(_Ept).xLocation - t_AllPts(_Spt).xLocation
            ByAy = t_AllPts(_Ept).yLocation - t_AllPts(_Spt).yLocation
            CxAx = AClick_X - t_AllPts(_Spt).xLocation
            DxCx = -xs + AClick_X
            DyCy = -ys + AClick_Y
            CyAy = AClick_Y - t_AllPts(_Spt).yLocation
            twoD_Linear_Solver(BxAx, DxCx, CxAx, ByAy, DyCy, CyAy, t, s)
            '---- Check whether the interection point falls between the segment ie., 0<t<1
            If t > 0 And t < 1 Then
                Dim intPtx, intPty As Double
                intPtx = 1
                intPty = 1
                Dim dist As Double
                dist = Math.Sqrt(Math.Pow((AClick_X - intPtx), 2) + Math.Pow((AClick_Y - intPty), 2))
                If Math.Round(dist, 2) < 5 Then '--- 5 is just arbitrary
                    '--- line is selected
                End If
            End If
        End Sub
    End Class

[||Pic: threeP1||]

[||Pic: threeP2||] <Line is Selected>

[||Pic: threeP3||]

Angle made by a line with horizontal axis

Below is the code implementation for finding the angle made by a line with origin

          Dim P1x, P1y, P2x, P2y As Double
            P1x = _AllEndpts(_Spt).xLocation
            P1y = _AllEndpts(_Spt).yLocation
            P2x = _AllEndpts(_Ept).xLocation
            P2y = _AllEndpts(_Ept).yLocation
            '--------------------------------------------------------
            Dim deltaX, deltaY As Double
            deltaY = Math.Abs(p2y - P1y)
            deltaX = Math.Abs(P2x - P1x)
           
            _AnglewithOrgin = Math.Atan2(deltaY, deltaX) '* (180 / Math.PI)
            If (P2y < P1y) Then 'Second point is lower than first, angle goes down (180-360)
                If (P2x < P1x) Then '//Second point is to the left of first (180-270)
                    _AnglewithOrgin = _AnglewithOrgin + (Math.PI) '-- 180 degree to 270 degree
                Else '(270-360)
                    _AnglewithOrgin = (2 * Math.PI) - _AnglewithOrgin  '-- 270 degree to 360 degree
                End If
            ElseIf (P2x < P1x) Then '//Second point is top left of first (90-180)
                _AnglewithOrgin = Math.PI - _AnglewithOrgin '-- 90 degree to 180 degree
            End If

[||Pic: fourP1||]

[||Pic: fourP2||]

[||Pic: fourP3||]

Angle between two lines

The angle between two lines is just the inner product of the vectors made by the lines. The simple implementation is below

  Public Sub Angle_Between_TwoLines2(ByVal X1 As Double, ByVal Y1 As Double, _
                                      ByVal X2 As Double, ByVal Y2 As Double, _
                                      ByVal X3 As Double, ByVal Y3 As Double, _
                                      ByVal X4 As Double, ByVal Y4 As Double, _
                                      ByRef _AngleB2Lines As Double)
        Dim Dx1, Dy1 As Double
        Dim Normalize1 As Double
        Dx1 = X2 - X1
        Dy1 = Y2 - Y1
        Normalize1 = Math.Sqrt((Dx1 * Dx1) + (Dy1 * Dy1))
        Dx1 = Dx1 / Normalize1
        Dy1 = Dy1 / Normalize1
        Dim Dx2, Dy2 As Double
        Dim Normalize2 As Double
        Dx2 = X4 - X3
        Dy2 = Y4 - Y3
        Normalize2 = Math.Sqrt((Dx2 * Dx2) + (Dy2 * Dy2))
        Dx2 = Dx2 / Normalize2
        Dy2 = Dy2 / Normalize2
        _AngleB2Lines = Math.Acos((Dx1 * Dx2) + (Dy1 * Dy2))
    End Sub

[||Pic: fiveP1||]

[||Pic: fiveP2||]

[||Pic: fiveP3||]