none
How to write a code to select an element (line or circle or fill of a circle) by mouse and your selection becomes of light gray instead of black RRS feed

  • Question

  • Hi All, 

    Hi Mr. Tommy,

    I thinking to input data by mouse but I am still have not any thing to start for selection by mouse.

    I will use select by mouse maybe after 4-5 months but I am interesting to know any thing about selection by mouse as soon as possible.

    How to write a code to select an element (line - circle - fill of a circle) by mouse and your selection becomes of light gray instead of black.

    Kind Regards,

     

      



    Hany Metry

    Sunday, November 24, 2019 9:26 PM

Answers

  • See Hany, this what Les talks about you have no explanation of what you mean. Poor George is lost from the start and has to waste time asking questions.

    I really dont follow what you did with your last thread with the "line intersecting" or why but it sort of looks like you ran off the tracks into the cactus patch? I guess you know why you did what you did. :)

    I think I now see and corrected the zoom fence lower left corner position accuracy you mentioned in previous threads. In the version 3 example I posted a few threads ago I rounded the origin offset pt corner with RoundToIncrement but for the corner point you dont need to do that. It could be an option. The rounding will sometimes make the position move slightly from exactly where you click with the red zoom fence.

    Version 4 example below has the find checkbox. When checked you can click on lines to select them and they are highlighted as you select. Uncheck the find checkbox when done selecting multiple objects.

    You can also use <ctrl key>+left mouse button to select an object without using the find button.

    Click the clear find button to clear selection.

    The example makes the controls just cut and paste the code into an empty form. Change the form name as required.

    'Line Drawing CAD Example version 4 positive y axis with mousewheel zoom, zoom rectangle fence,
    '   snap to grid, Find check Button or ctrl+LMB to select object
    
    Public Class Form4
        Private WithEvents Picturebox1 As New PictureBox With {.Parent = Me, .BackColor = Color.White}
        Private WithEvents LineCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(10, 60), .Size = New Size(60, 24), .Text = "Line", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Line"}
        Private WithEvents LineMultiCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(10, 100), .Size = New Size(60, 24), .Text = "MultiLine", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "LineMulti"}
        Private WithEvents ZoomFenceCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(80, 10), .Size = New Size(80, 24), .Text = "Zoom Fence", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Zoom Fence"}
        Private WithEvents ZoomOutBtn As New Button With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(160, 10), .Size = New Size(80, 24), .Text = "Zoom Out",
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Zoom Out"}
        Private WithEvents FindCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(260, 10), .Size = New Size(80, 24), .Text = "Find", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Find"}
        Private WithEvents FindClearBtn As New Button With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(340, 10), .Size = New Size(80, 24), .Text = "Find Clear",
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Clear Find"}
        Private WithEvents SnapCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(440, 10), .Size = New Size(60, 24), .Text = "Snap"}
    
        Public Class Shape
            Public pt1 As PointF
            Public pt2 As PointF
            Public color As Color = Color.Red
    
            Public Sub Draw(g As Graphics, yOffset1 As Single, HighLight As Boolean)
                Dim clr As Color
                If HighLight Then clr = Color.GreenYellow Else clr = color
    
                Using p As New Pen(clr, g.VisibleClipBounds.Width / 100)
                    g.DrawLine(p, pt1.X, yOffset1 - pt1.Y, pt2.X, yOffset1 - pt2.Y)
                End Using
            End Sub
        End Class
    
        Private Shapes As New List(Of Shape)
        Private FoundObjects As New List(Of Integer)
        Private ScaleWidthDefault As Single = 100000
        Private ScaleWidth As Single = ScaleWidthDefault
        Private ScaleRatio As Single = 1
        Private Yoffset As Single
        Private Corner As New PointF(0, 0)
        Private GridStep As Single
        Private SnapStep As Single
        Private MouseDownPt, MouseMovePt, ZoomMouseDownPt, ZoomMouseMovePt As PointF
        Private MouseDownCornerPt As PointF
        Private MouseStatus As Integer
        Private ToolCbCancel As Boolean = False
        Private SelectedTool As String
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ClientSize = New Size(500, 320)
            DoubleBuffered = True
            Text = "Line drawing Example"
            BackColor = Color.BurlyWood
            LineCb.FlatAppearance.CheckedBackColor = Color.AliceBlue
            LineMultiCb.FlatAppearance.CheckedBackColor = Color.AliceBlue
            ZoomFenceCb.FlatAppearance.CheckedBackColor = Color.LightSalmon
            FindCb.FlatAppearance.CheckedBackColor = Color.LightSalmon
            LineCb.Checked = True
    
            'draw initial view
            GetGridStep()
    
            Form2_Resize(0, Nothing)
            Picturebox1.Focus()
        End Sub
    
        Private Sub Form2_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            Dim border As Integer = 20
            Picturebox1.Location = New Point(80, 50)
            Picturebox1.Size = New Size(ClientSize.Width - (border + Picturebox1.Left), ClientSize.Height - (50 + border))
            Yoffset = ScaleWidth * (Picturebox1.ClientSize.Height / Picturebox1.ClientSize.Width)
            Picturebox1.Invalidate()
    
        End Sub
    
        Private Sub Picturebox1_MouseDown(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseDown
            Dim pt As PointF = GetScalePtFromClientPt(e.Location)
    
            If ZoomFenceCb.Checked Then
                'keep zoom independant of drawing tools to allow nesting of zoom with tools.
                ZoomMouseDownPt = pt
                ZoomMouseMovePt = pt
            Else
                Select Case SelectedTool
                    Case "LineMulti"
                        'for multiline dont need to set mouse down
                        If MouseStatus = 0 Then MouseDownPt = pt
                    Case Else
                        MouseDownPt = pt
                End Select
            End If
    
            MouseStatus = 1
            MouseMovePt = MouseDownPt
            MouseDownCornerPt = Corner
    
            If e.Button = MouseButtons.Right Then MouseStatus = 0
    
            Picturebox1.Focus()
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub Picturebox1_MouseMove(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseMove
            Dim pt As PointF = GetScalePtFromClientPt(e.Location)
            pt = SnapToGrid(pt)
    
            If e.Button = MouseButtons.Right Then
                'calc scale coords using MouseDownCornerPt as corner is changing while dragging
                Dim dx As Double = (MouseDownCornerPt.X + (e.X * ScaleRatio)) - MouseDownPt.X
                Dim dy As Double = (MouseDownCornerPt.Y + (e.Y * ScaleRatio)) - (Yoffset - MouseDownPt.Y)
    
                Corner = New Point(CSng(MouseDownCornerPt.X - dx), CSng(MouseDownCornerPt.Y - dy))
    
                Picturebox1.Invalidate()
    
            Else
                Select Case MouseStatus
                    Case 1
                        If ZoomFenceCb.Checked Then
                            ZoomMouseMovePt = pt
                        Else
                            MouseMovePt = pt
    
                        End If
    
                        Picturebox1.Invalidate()
                End Select
            End If
        End Sub
    
        Private Sub Picturebox1_MouseUp(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseUp
            If e.Button = MouseButtons.Right Then
                MouseStatus = 0
            Else
                Dim pt As PointF = GetScalePtFromClientPt(e.Location)
                pt = SnapToGrid(pt)
    
                Select Case MouseStatus
                    Case 1
                        If ZoomFenceCb.Checked Then
                            ZoomMouseMovePt = pt
                            ZoomFenceCb.Checked = False
                            'set scale based on zoom rect
                            Dim dx As Integer = ZoomMouseMovePt.X - ZoomMouseDownPt.X
                            Dim dy As Integer = ZoomMouseMovePt.Y - ZoomMouseDownPt.Y
                            ScaleWidth = dx
                            GetGridStep()
    
                            'set origin v4 correction remove rounding
                            Corner.X = ZoomMouseDownPt.X
                            Corner.Y = ZoomMouseDownPt.Y + dy
    
                            MouseStatus = 0
    
                            'update yoffset etc
                            Form2_Resize(0, Nothing)
    
                        ElseIf sender.modifierkeys = 131072 Or FindCb.checked Then
                            'if checkbox or ctrl key pressed down find object
                            Dim FoundObject As Integer = FindObject(pt)
                            If FoundObject > -1 Then
                                FoundObjects.Add(FoundObject)
                                MouseStatus = 0
                            End If
    
                        Else
    
                            MouseMovePt = pt
                            Dim shp As New Shape
                            shp.pt1 = MouseDownPt
                            shp.pt2 = MouseMovePt
                            shp.color = Color.Red
                            Shapes.Add(shp)
    
                            Select Case SelectedTool
                                Case "LineMulti"
                                    'for multiline repeat last point as new second point
                                    MouseStatus = 1
                                    MouseDownPt = shp.pt2
    
                                Case Else
                                    MouseStatus = 0
                            End Select
                        End If
                End Select
            End If
    
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub Picturebox1_MouseWheel(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseWheel
            ScaleRatio += Math.Sign(e.Delta) * 0.1
            If ScaleRatio < 0.000001 Then ScaleRatio = 0.000001
            If ScaleRatio > 10000 Then ScaleRatio = 10000
    
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub Picturebox1_MouseEnter(sender As Object, e As EventArgs) Handles Picturebox1.MouseEnter
            'need this for mouse wheel
            Picturebox1.Focus()
        End Sub
    
        Private Sub Picturebox1_Paint(sender As Object, e As PaintEventArgs) Handles Picturebox1.Paint
    
            With e.Graphics
                .ResetTransform()
                .Clear(Color.White)
                .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    
                Dim sf As Single = CSng(Picturebox1.ClientSize.Width / (ScaleRatio * ScaleWidth))
                .ScaleTransform(sf, sf)
                .TranslateTransform(-Corner.X, Corner.Y)
    
                DrawGrid(e.Graphics)
    
                For Each shp As Shape In Shapes
                    shp.Draw(e.Graphics, Yoffset, False)
                Next
    
    
                Select Case MouseStatus
                    Case 1  'draw line tracers
                        If ZoomFenceCb.Checked Then
                            'convert for positive yaxis and rectf
                            Dim zoomrect As New Rectangle(ZoomMouseDownPt.X,
                                                          Yoffset - ZoomMouseDownPt.Y,
                                                          ZoomMouseMovePt.X - ZoomMouseDownPt.X,
                                                          ZoomMouseDownPt.Y - ZoomMouseMovePt.Y)
    
                            .DrawRectangle(Pens.Red, zoomrect)
                        Else
                            .DrawLine(New Pen(Color.Red, .VisibleClipBounds.Width / 100), MouseDownPt.X, Yoffset - MouseDownPt.Y, MouseMovePt.X, Yoffset - MouseMovePt.Y)
                        End If
                End Select
    
                If FoundObjects.Count > 0 Then
                    For i As Integer = 0 To FoundObjects.Count - 1
                        Shapes(FoundObjects(i)).Draw(e.Graphics, Yoffset, True)
                    Next
    
                End If
            End With
        End Sub
    
        Private Sub DrawGrid(g As Graphics)
            'setup drawing corners etc
            Dim x1 As Single = RoundToIncrement(Corner.X - GridStep, CInt(GridStep))
            Dim y1 As Single = RoundToIncrement(Corner.Y - GridStep, CInt(GridStep))
            Dim sw As Single = CSng(ScaleRatio * ScaleWidth + (2 * GridStep))
            Dim pxlSize As Single = ScaleRatio * ScaleWidth / Picturebox1.ClientSize.Width
    
            With g
                Using pg As New Pen(Color.DarkGray, CSng(pxlSize / 6)),
                        pgrn As New Pen(Color.Green, CSng(pxlSize / 6)),
                        f As New Font("arial", CSng(11 * pxlSize)),
                        br As New SolidBrush(Color.DimGray)
    
                    'draw origin
                    .DrawLine(pgrn, -pxlSize, Yoffset, pxlSize, Yoffset)
                    .DrawLine(pgrn, 0, Yoffset - (-pxlSize), 0, Yoffset - pxlSize)
    
                    'x axis grid
                    For x As Single = x1 To CSng(x1 + sw) Step GridStep
                        .DrawLine(pg, x, Yoffset - y1, x, Yoffset - CSng(y1 + sw))
                        .DrawString(x.ToString, f, br, x, Yoffset - (Corner.Y + (20 * pxlSize)))
                    Next
    
                    For y As Single = y1 To CSng(y1 + sw) Step GridStep
                        .DrawLine(pg, x1, Yoffset - y, CSng(x1 + sw), Yoffset - y)
                        .DrawString(y.ToString, f, br, Corner.X, Yoffset - y)
                    Next
                End Using
            End With
        End Sub
    
        Private Function SnapToGrid(thispt As PointF) As PointF
            Dim x, y As Single
    
            If SnapCb.Checked Then
                x = CInt(thispt.X / SnapStep) * SnapStep
                y = CInt(thispt.Y / SnapStep) * SnapStep
            Else
                x = thispt.X
                y = thispt.Y
            End If
    
            Return New PointF(x, y)
        End Function
    
        Private Function RoundToIncrement(theValue As Double, roundIncrement As Integer) As Integer
            'ie value = 1433 roundinc = 100 returns 1400
            Return CInt((CDbl(theValue) + (0.5 * roundIncrement)) / roundIncrement) * roundIncrement
        End Function
    
        Private Function GetScalePtFromClientPt(pt As PointF) As PointF
            'convert screen pixels to scale drawing coords
            Dim sf As Double = Picturebox1.ClientSize.Width / (ScaleWidth * ScaleRatio)
            Return New PointF(CSng(Corner.X + (pt.X / sf)), CSng(Corner.Y + (Yoffset - pt.Y / sf)))
        End Function
    
        Private Sub Tools_CheckedChanged(sender As Object, e As EventArgs) Handles _
            LineCb.CheckedChanged, LineMultiCb.CheckedChanged
    
            If ToolCbCancel = False Then
                ToolCbCancel = True
                Select Case DirectCast(sender, CheckBox).Name
                    Case "Line"
                        If LineCb.Checked = True Then
                            SelectedTool = "Line"
                            LineMultiCb.Checked = False
                        End If
                    Case "LineMulti"
                        SelectedTool = "LineMulti"
                        If LineMultiCb.Checked = True Then LineCb.Checked = False
                End Select
            End If
    
            ToolCbCancel = False
            MouseStatus = 0
        End Sub
    
        Private Sub ZoomOutBtn_Click(sender As Object, e As EventArgs) Handles ZoomOutBtn.Click
            ScaleWidth = ScaleWidthDefault
            GetGridStep()
            'set origin
            Corner.X = 0
            Corner.Y = 0
    
            'update yoffset etc
            Form2_Resize(0, Nothing)
        End Sub
    
        Private Sub ZoomFenceCb_CheckedChanged(sender As Object, e As EventArgs) Handles ZoomFenceCb.CheckedChanged
            If FindCb.Checked AndAlso ToolCbCancel = False Then
                ToolCbCancel = True
                FindCb.Checked = False
                ToolCbCancel = False
            End If
    
        End Sub
    
        Private Sub FindCb_CheckedChanged(sender As Object, e As EventArgs) Handles FindCb.CheckedChanged
            If ZoomFenceCb.Checked AndAlso ToolCbCancel = False Then
                ToolCbCancel = True
                ZoomFenceCb.Checked = False
                ToolCbCancel = False
            End If
    
        End Sub
    
        Private Sub FindClearBtn_MouseClick(sender As Object, e As MouseEventArgs) Handles FindClearBtn.MouseClick
            FoundObjects.Clear()
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub GetGridStep()
            Dim ratio As Single = 10
    
            Select Case Math.Floor(ScaleWidth / 10)
                Case < 1000
                    GridStep = 100 * ratio
                Case < 2000
                    GridStep = 200 * ratio
                Case < 5000
                    GridStep = 500 * ratio
                Case < 10000
                    GridStep = 1000 * ratio
                Case < 20000
                    GridStep = 2000 * ratio
                Case < 50000
                    GridStep = 5000 * ratio
                Case < 100000
                    GridStep = 10000 * ratio
            End Select
            SnapStep = GridStep
    
        End Sub
    
        Public Function FindObject(ByVal Pt As PointF) As Integer
            Dim minIndex As Integer = -1
            Dim minDistance As Double = 10000000000000
            Dim thisDistance As Double
            Dim foundAlready As Boolean
    
            For i As Integer = 0 To Shapes.Count - 1
                foundAlready = False
    
                For foundobject As Integer = 0 To FoundObjects.Count - 1
                    If FoundObjects(foundobject) = i Then foundAlready = True
                Next
    
                If Not foundAlready Then
                    thisDistance = GetPointToLineDistance(Shapes(i), Pt)
                    If thisDistance < minDistance Then
                        minDistance = thisDistance
                        minIndex = i
                        Exit For
                    End If
                End If
            Next
    
            Return minIndex
        End Function
    
        Private Function GetPointToLineDistance(Shp As Shape, Pt As PointF) As Double
            Dim ldx1, ldy1, ldx2, ldy2, tolerance As Double
            Dim ldx, ldy, lslope, lsyint As Double
            Dim minDistance As Double = 10000000000000
    
            ldx1 = Shp.pt1.X
            ldy1 = Shp.pt1.Y
            ldx2 = Shp.pt2.X
            ldy2 = Shp.pt2.Y
    
            tolerance = ScaleWidth / 100
    
            If ldx1 > ldx2 Then
                'these points are not always sorted
                TOMSWAP(ldx1, ldx2)
                TOMSWAP(ldy1, ldy2)
            End If
    
            'distance from point to line
            ldx = CheckZero(ldx2 - ldx1)
            ldy = CheckZero(ldy2 - ldy1)
            lslope = CheckZero(ldy / ldx)
            lsyint = ldy2 - (lslope * ldx2)
    
            Dim d2 As Double = ((lslope * lslope) + 1)
            If d2 < 0.00001 Then d2 = 0.00001
            d2 = Math.Abs(lsyint + (lslope * Pt.X) - Pt.Y) / Math.Sqrt(d2)
    
            If d2 < tolerance Then
                'adjust for vertical and horz lines
                If Math.Abs(lslope) < 1 Then
                    'check pt between endpoints
                    'need this for multiple short lines end to end 
                    If ldx1 - (tolerance / 4) < Pt.X And ldx2 + (tolerance / 4) > Pt.X Then
                        If d2 < minDistance Then
                            minDistance = d2
                        End If
                    End If
                Else
                    If ldy1 > ldy2 Then
                        If ldy1 + (tolerance / 4) > Pt.Y And ldy2 - (tolerance / 4) < Pt.Y Then
                            'between ends so ok
                            If d2 < minDistance Then
                                minDistance = d2
                            End If
                        End If
                    Else
                        If ldy1 - (tolerance / 4) < Pt.Y And ldy2 + (tolerance / 4) > Pt.Y Then
                            If d2 < minDistance Then
                                minDistance = d2
                            End If
                        End If
                    End If
                End If
            End If
    
            Return minDistance
    
        End Function
    
        Public Function CheckZero(ByVal czvalue As Double) As Double
            If czvalue = 0 Then CheckZero = 0.000000000001 Else CheckZero = czvalue
        End Function
    
        Public Sub TOMSWAP(ByRef t1 As Double, ByRef t2 As Double)
            Dim t As Double
            t = t1
            t1 = t2
            t2 = t
        End Sub
    End Class
    
    

    • Marked as answer by Hany Metry Monday, November 25, 2019 4:35 AM
    Monday, November 25, 2019 4:14 AM

All replies

  • Do you have ANY code that you wrote by yourself? It seems to me that you are here to get everyone else to create your application for you - then you will try and sell it!

    Regards Les, Livingston, Scotland

    Sunday, November 24, 2019 9:30 PM
  • Do you have ANY code that you wrote by yourself? It seems to me that you are here to get everyone else to create your application for you - then you will try and sell it!

    Regards Les, Livingston, Scotland

    The application is very large and I want guide simple code and then, I will modify the code to be applicable for general case.

    I am write the question to learn and I don't asked any one to write the code of my application.

    That I still in learning stage.



    Hany Metry

    Sunday, November 24, 2019 9:46 PM
  • If you are using WPF...

    XAML

    <Ellipse Name="elpGraphic1" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="430,159,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>


    Visual Basic

        Private Sub elpGraphic1_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles elpGraphic1.MouseDown
            elpGraphic1.Fill = Brushes.BurlyWood
        End Sub



    George Frias (Wikidot AWWshop)

    • Marked as answer by Hany Metry Monday, November 25, 2019 3:21 AM
    • Unmarked as answer by Hany Metry Monday, November 25, 2019 3:21 AM
    Sunday, November 24, 2019 10:58 PM
  • If you are using WPF...

    XAML

    <Ellipse Name="elpGraphic1" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="430,159,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>


    Visual Basic

        Private Sub elpGraphic1_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles elpGraphic1.MouseDown
            elpGraphic1.Fill = Brushes.BurlyWood
        End Sub



    George Frias (Wikidot AWWshop)

    Hi George,

    I am using visual basic and I don't know WPF

    Kind Regards,


    Hany Metry

    Monday, November 25, 2019 2:52 AM
  • You can be using Windows Forms (most likely the case), WPF, or UWP. They all come in Visual Basic flavors.


    George Frias - AWWshop @: Wikidot, GitHub

    Monday, November 25, 2019 2:57 AM
  • If you are using WPF...

    XAML

    <Ellipse Name="elpGraphic1" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="430,159,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>


    Visual Basic

        Private Sub elpGraphic1_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles elpGraphic1.MouseDown
            elpGraphic1.Fill = Brushes.BurlyWood
        End Sub



    George Frias (Wikidot AWWshop)

    That code to Fill and not select and I want code to select what you drawn by mouse.

    Hany Metry

    Monday, November 25, 2019 3:24 AM
  • Select. In what way?

    A border?

    As far as I know you can focus a control.

    Something like tbx.Focus should work.


    George Frias - AWWshop @: Wikidot, GitHub

    Monday, November 25, 2019 3:38 AM
  • Is the code in that site correct. Is the code in that site, will be the start of thinking.


    http://forums.codeguru.com/showthread.php?419763-Check-a-Point-lies-in-a-Line-segment



    Hany Metry


    • Edited by Hany Metry Monday, November 25, 2019 4:04 AM
    Monday, November 25, 2019 4:03 AM
  • Select. In what way?

    A border?

    As far as I know you can focus a control.

    Something like tbx.Focus should work.


    George Frias - AWWshop @: Wikidot, GitHub

    If I don't learn how to select item by mouse, I will cancel to input item by mouse in my application.

    Hany Metry

    Monday, November 25, 2019 4:08 AM
  • See Hany, this what Les talks about you have no explanation of what you mean. Poor George is lost from the start and has to waste time asking questions.

    I really dont follow what you did with your last thread with the "line intersecting" or why but it sort of looks like you ran off the tracks into the cactus patch? I guess you know why you did what you did. :)

    I think I now see and corrected the zoom fence lower left corner position accuracy you mentioned in previous threads. In the version 3 example I posted a few threads ago I rounded the origin offset pt corner with RoundToIncrement but for the corner point you dont need to do that. It could be an option. The rounding will sometimes make the position move slightly from exactly where you click with the red zoom fence.

    Version 4 example below has the find checkbox. When checked you can click on lines to select them and they are highlighted as you select. Uncheck the find checkbox when done selecting multiple objects.

    You can also use <ctrl key>+left mouse button to select an object without using the find button.

    Click the clear find button to clear selection.

    The example makes the controls just cut and paste the code into an empty form. Change the form name as required.

    'Line Drawing CAD Example version 4 positive y axis with mousewheel zoom, zoom rectangle fence,
    '   snap to grid, Find check Button or ctrl+LMB to select object
    
    Public Class Form4
        Private WithEvents Picturebox1 As New PictureBox With {.Parent = Me, .BackColor = Color.White}
        Private WithEvents LineCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(10, 60), .Size = New Size(60, 24), .Text = "Line", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Line"}
        Private WithEvents LineMultiCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(10, 100), .Size = New Size(60, 24), .Text = "MultiLine", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "LineMulti"}
        Private WithEvents ZoomFenceCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(80, 10), .Size = New Size(80, 24), .Text = "Zoom Fence", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Zoom Fence"}
        Private WithEvents ZoomOutBtn As New Button With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(160, 10), .Size = New Size(80, 24), .Text = "Zoom Out",
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Zoom Out"}
        Private WithEvents FindCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(260, 10), .Size = New Size(80, 24), .Text = "Find", .Appearance = Appearance.Button,
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Find"}
        Private WithEvents FindClearBtn As New Button With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(340, 10), .Size = New Size(80, 24), .Text = "Find Clear",
            .BackColor = Color.AntiqueWhite, .TextAlign = ContentAlignment.MiddleCenter, .Name = "Clear Find"}
        Private WithEvents SnapCb As New CheckBox With {.Parent = Me, .FlatStyle = FlatStyle.Flat,
            .Location = New Point(440, 10), .Size = New Size(60, 24), .Text = "Snap"}
    
        Public Class Shape
            Public pt1 As PointF
            Public pt2 As PointF
            Public color As Color = Color.Red
    
            Public Sub Draw(g As Graphics, yOffset1 As Single, HighLight As Boolean)
                Dim clr As Color
                If HighLight Then clr = Color.GreenYellow Else clr = color
    
                Using p As New Pen(clr, g.VisibleClipBounds.Width / 100)
                    g.DrawLine(p, pt1.X, yOffset1 - pt1.Y, pt2.X, yOffset1 - pt2.Y)
                End Using
            End Sub
        End Class
    
        Private Shapes As New List(Of Shape)
        Private FoundObjects As New List(Of Integer)
        Private ScaleWidthDefault As Single = 100000
        Private ScaleWidth As Single = ScaleWidthDefault
        Private ScaleRatio As Single = 1
        Private Yoffset As Single
        Private Corner As New PointF(0, 0)
        Private GridStep As Single
        Private SnapStep As Single
        Private MouseDownPt, MouseMovePt, ZoomMouseDownPt, ZoomMouseMovePt As PointF
        Private MouseDownCornerPt As PointF
        Private MouseStatus As Integer
        Private ToolCbCancel As Boolean = False
        Private SelectedTool As String
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ClientSize = New Size(500, 320)
            DoubleBuffered = True
            Text = "Line drawing Example"
            BackColor = Color.BurlyWood
            LineCb.FlatAppearance.CheckedBackColor = Color.AliceBlue
            LineMultiCb.FlatAppearance.CheckedBackColor = Color.AliceBlue
            ZoomFenceCb.FlatAppearance.CheckedBackColor = Color.LightSalmon
            FindCb.FlatAppearance.CheckedBackColor = Color.LightSalmon
            LineCb.Checked = True
    
            'draw initial view
            GetGridStep()
    
            Form2_Resize(0, Nothing)
            Picturebox1.Focus()
        End Sub
    
        Private Sub Form2_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            Dim border As Integer = 20
            Picturebox1.Location = New Point(80, 50)
            Picturebox1.Size = New Size(ClientSize.Width - (border + Picturebox1.Left), ClientSize.Height - (50 + border))
            Yoffset = ScaleWidth * (Picturebox1.ClientSize.Height / Picturebox1.ClientSize.Width)
            Picturebox1.Invalidate()
    
        End Sub
    
        Private Sub Picturebox1_MouseDown(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseDown
            Dim pt As PointF = GetScalePtFromClientPt(e.Location)
    
            If ZoomFenceCb.Checked Then
                'keep zoom independant of drawing tools to allow nesting of zoom with tools.
                ZoomMouseDownPt = pt
                ZoomMouseMovePt = pt
            Else
                Select Case SelectedTool
                    Case "LineMulti"
                        'for multiline dont need to set mouse down
                        If MouseStatus = 0 Then MouseDownPt = pt
                    Case Else
                        MouseDownPt = pt
                End Select
            End If
    
            MouseStatus = 1
            MouseMovePt = MouseDownPt
            MouseDownCornerPt = Corner
    
            If e.Button = MouseButtons.Right Then MouseStatus = 0
    
            Picturebox1.Focus()
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub Picturebox1_MouseMove(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseMove
            Dim pt As PointF = GetScalePtFromClientPt(e.Location)
            pt = SnapToGrid(pt)
    
            If e.Button = MouseButtons.Right Then
                'calc scale coords using MouseDownCornerPt as corner is changing while dragging
                Dim dx As Double = (MouseDownCornerPt.X + (e.X * ScaleRatio)) - MouseDownPt.X
                Dim dy As Double = (MouseDownCornerPt.Y + (e.Y * ScaleRatio)) - (Yoffset - MouseDownPt.Y)
    
                Corner = New Point(CSng(MouseDownCornerPt.X - dx), CSng(MouseDownCornerPt.Y - dy))
    
                Picturebox1.Invalidate()
    
            Else
                Select Case MouseStatus
                    Case 1
                        If ZoomFenceCb.Checked Then
                            ZoomMouseMovePt = pt
                        Else
                            MouseMovePt = pt
    
                        End If
    
                        Picturebox1.Invalidate()
                End Select
            End If
        End Sub
    
        Private Sub Picturebox1_MouseUp(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseUp
            If e.Button = MouseButtons.Right Then
                MouseStatus = 0
            Else
                Dim pt As PointF = GetScalePtFromClientPt(e.Location)
                pt = SnapToGrid(pt)
    
                Select Case MouseStatus
                    Case 1
                        If ZoomFenceCb.Checked Then
                            ZoomMouseMovePt = pt
                            ZoomFenceCb.Checked = False
                            'set scale based on zoom rect
                            Dim dx As Integer = ZoomMouseMovePt.X - ZoomMouseDownPt.X
                            Dim dy As Integer = ZoomMouseMovePt.Y - ZoomMouseDownPt.Y
                            ScaleWidth = dx
                            GetGridStep()
    
                            'set origin v4 correction remove rounding
                            Corner.X = ZoomMouseDownPt.X
                            Corner.Y = ZoomMouseDownPt.Y + dy
    
                            MouseStatus = 0
    
                            'update yoffset etc
                            Form2_Resize(0, Nothing)
    
                        ElseIf sender.modifierkeys = 131072 Or FindCb.checked Then
                            'if checkbox or ctrl key pressed down find object
                            Dim FoundObject As Integer = FindObject(pt)
                            If FoundObject > -1 Then
                                FoundObjects.Add(FoundObject)
                                MouseStatus = 0
                            End If
    
                        Else
    
                            MouseMovePt = pt
                            Dim shp As New Shape
                            shp.pt1 = MouseDownPt
                            shp.pt2 = MouseMovePt
                            shp.color = Color.Red
                            Shapes.Add(shp)
    
                            Select Case SelectedTool
                                Case "LineMulti"
                                    'for multiline repeat last point as new second point
                                    MouseStatus = 1
                                    MouseDownPt = shp.pt2
    
                                Case Else
                                    MouseStatus = 0
                            End Select
                        End If
                End Select
            End If
    
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub Picturebox1_MouseWheel(sender As Object, e As MouseEventArgs) Handles Picturebox1.MouseWheel
            ScaleRatio += Math.Sign(e.Delta) * 0.1
            If ScaleRatio < 0.000001 Then ScaleRatio = 0.000001
            If ScaleRatio > 10000 Then ScaleRatio = 10000
    
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub Picturebox1_MouseEnter(sender As Object, e As EventArgs) Handles Picturebox1.MouseEnter
            'need this for mouse wheel
            Picturebox1.Focus()
        End Sub
    
        Private Sub Picturebox1_Paint(sender As Object, e As PaintEventArgs) Handles Picturebox1.Paint
    
            With e.Graphics
                .ResetTransform()
                .Clear(Color.White)
                .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    
                Dim sf As Single = CSng(Picturebox1.ClientSize.Width / (ScaleRatio * ScaleWidth))
                .ScaleTransform(sf, sf)
                .TranslateTransform(-Corner.X, Corner.Y)
    
                DrawGrid(e.Graphics)
    
                For Each shp As Shape In Shapes
                    shp.Draw(e.Graphics, Yoffset, False)
                Next
    
    
                Select Case MouseStatus
                    Case 1  'draw line tracers
                        If ZoomFenceCb.Checked Then
                            'convert for positive yaxis and rectf
                            Dim zoomrect As New Rectangle(ZoomMouseDownPt.X,
                                                          Yoffset - ZoomMouseDownPt.Y,
                                                          ZoomMouseMovePt.X - ZoomMouseDownPt.X,
                                                          ZoomMouseDownPt.Y - ZoomMouseMovePt.Y)
    
                            .DrawRectangle(Pens.Red, zoomrect)
                        Else
                            .DrawLine(New Pen(Color.Red, .VisibleClipBounds.Width / 100), MouseDownPt.X, Yoffset - MouseDownPt.Y, MouseMovePt.X, Yoffset - MouseMovePt.Y)
                        End If
                End Select
    
                If FoundObjects.Count > 0 Then
                    For i As Integer = 0 To FoundObjects.Count - 1
                        Shapes(FoundObjects(i)).Draw(e.Graphics, Yoffset, True)
                    Next
    
                End If
            End With
        End Sub
    
        Private Sub DrawGrid(g As Graphics)
            'setup drawing corners etc
            Dim x1 As Single = RoundToIncrement(Corner.X - GridStep, CInt(GridStep))
            Dim y1 As Single = RoundToIncrement(Corner.Y - GridStep, CInt(GridStep))
            Dim sw As Single = CSng(ScaleRatio * ScaleWidth + (2 * GridStep))
            Dim pxlSize As Single = ScaleRatio * ScaleWidth / Picturebox1.ClientSize.Width
    
            With g
                Using pg As New Pen(Color.DarkGray, CSng(pxlSize / 6)),
                        pgrn As New Pen(Color.Green, CSng(pxlSize / 6)),
                        f As New Font("arial", CSng(11 * pxlSize)),
                        br As New SolidBrush(Color.DimGray)
    
                    'draw origin
                    .DrawLine(pgrn, -pxlSize, Yoffset, pxlSize, Yoffset)
                    .DrawLine(pgrn, 0, Yoffset - (-pxlSize), 0, Yoffset - pxlSize)
    
                    'x axis grid
                    For x As Single = x1 To CSng(x1 + sw) Step GridStep
                        .DrawLine(pg, x, Yoffset - y1, x, Yoffset - CSng(y1 + sw))
                        .DrawString(x.ToString, f, br, x, Yoffset - (Corner.Y + (20 * pxlSize)))
                    Next
    
                    For y As Single = y1 To CSng(y1 + sw) Step GridStep
                        .DrawLine(pg, x1, Yoffset - y, CSng(x1 + sw), Yoffset - y)
                        .DrawString(y.ToString, f, br, Corner.X, Yoffset - y)
                    Next
                End Using
            End With
        End Sub
    
        Private Function SnapToGrid(thispt As PointF) As PointF
            Dim x, y As Single
    
            If SnapCb.Checked Then
                x = CInt(thispt.X / SnapStep) * SnapStep
                y = CInt(thispt.Y / SnapStep) * SnapStep
            Else
                x = thispt.X
                y = thispt.Y
            End If
    
            Return New PointF(x, y)
        End Function
    
        Private Function RoundToIncrement(theValue As Double, roundIncrement As Integer) As Integer
            'ie value = 1433 roundinc = 100 returns 1400
            Return CInt((CDbl(theValue) + (0.5 * roundIncrement)) / roundIncrement) * roundIncrement
        End Function
    
        Private Function GetScalePtFromClientPt(pt As PointF) As PointF
            'convert screen pixels to scale drawing coords
            Dim sf As Double = Picturebox1.ClientSize.Width / (ScaleWidth * ScaleRatio)
            Return New PointF(CSng(Corner.X + (pt.X / sf)), CSng(Corner.Y + (Yoffset - pt.Y / sf)))
        End Function
    
        Private Sub Tools_CheckedChanged(sender As Object, e As EventArgs) Handles _
            LineCb.CheckedChanged, LineMultiCb.CheckedChanged
    
            If ToolCbCancel = False Then
                ToolCbCancel = True
                Select Case DirectCast(sender, CheckBox).Name
                    Case "Line"
                        If LineCb.Checked = True Then
                            SelectedTool = "Line"
                            LineMultiCb.Checked = False
                        End If
                    Case "LineMulti"
                        SelectedTool = "LineMulti"
                        If LineMultiCb.Checked = True Then LineCb.Checked = False
                End Select
            End If
    
            ToolCbCancel = False
            MouseStatus = 0
        End Sub
    
        Private Sub ZoomOutBtn_Click(sender As Object, e As EventArgs) Handles ZoomOutBtn.Click
            ScaleWidth = ScaleWidthDefault
            GetGridStep()
            'set origin
            Corner.X = 0
            Corner.Y = 0
    
            'update yoffset etc
            Form2_Resize(0, Nothing)
        End Sub
    
        Private Sub ZoomFenceCb_CheckedChanged(sender As Object, e As EventArgs) Handles ZoomFenceCb.CheckedChanged
            If FindCb.Checked AndAlso ToolCbCancel = False Then
                ToolCbCancel = True
                FindCb.Checked = False
                ToolCbCancel = False
            End If
    
        End Sub
    
        Private Sub FindCb_CheckedChanged(sender As Object, e As EventArgs) Handles FindCb.CheckedChanged
            If ZoomFenceCb.Checked AndAlso ToolCbCancel = False Then
                ToolCbCancel = True
                ZoomFenceCb.Checked = False
                ToolCbCancel = False
            End If
    
        End Sub
    
        Private Sub FindClearBtn_MouseClick(sender As Object, e As MouseEventArgs) Handles FindClearBtn.MouseClick
            FoundObjects.Clear()
            Picturebox1.Invalidate()
        End Sub
    
        Private Sub GetGridStep()
            Dim ratio As Single = 10
    
            Select Case Math.Floor(ScaleWidth / 10)
                Case < 1000
                    GridStep = 100 * ratio
                Case < 2000
                    GridStep = 200 * ratio
                Case < 5000
                    GridStep = 500 * ratio
                Case < 10000
                    GridStep = 1000 * ratio
                Case < 20000
                    GridStep = 2000 * ratio
                Case < 50000
                    GridStep = 5000 * ratio
                Case < 100000
                    GridStep = 10000 * ratio
            End Select
            SnapStep = GridStep
    
        End Sub
    
        Public Function FindObject(ByVal Pt As PointF) As Integer
            Dim minIndex As Integer = -1
            Dim minDistance As Double = 10000000000000
            Dim thisDistance As Double
            Dim foundAlready As Boolean
    
            For i As Integer = 0 To Shapes.Count - 1
                foundAlready = False
    
                For foundobject As Integer = 0 To FoundObjects.Count - 1
                    If FoundObjects(foundobject) = i Then foundAlready = True
                Next
    
                If Not foundAlready Then
                    thisDistance = GetPointToLineDistance(Shapes(i), Pt)
                    If thisDistance < minDistance Then
                        minDistance = thisDistance
                        minIndex = i
                        Exit For
                    End If
                End If
            Next
    
            Return minIndex
        End Function
    
        Private Function GetPointToLineDistance(Shp As Shape, Pt As PointF) As Double
            Dim ldx1, ldy1, ldx2, ldy2, tolerance As Double
            Dim ldx, ldy, lslope, lsyint As Double
            Dim minDistance As Double = 10000000000000
    
            ldx1 = Shp.pt1.X
            ldy1 = Shp.pt1.Y
            ldx2 = Shp.pt2.X
            ldy2 = Shp.pt2.Y
    
            tolerance = ScaleWidth / 100
    
            If ldx1 > ldx2 Then
                'these points are not always sorted
                TOMSWAP(ldx1, ldx2)
                TOMSWAP(ldy1, ldy2)
            End If
    
            'distance from point to line
            ldx = CheckZero(ldx2 - ldx1)
            ldy = CheckZero(ldy2 - ldy1)
            lslope = CheckZero(ldy / ldx)
            lsyint = ldy2 - (lslope * ldx2)
    
            Dim d2 As Double = ((lslope * lslope) + 1)
            If d2 < 0.00001 Then d2 = 0.00001
            d2 = Math.Abs(lsyint + (lslope * Pt.X) - Pt.Y) / Math.Sqrt(d2)
    
            If d2 < tolerance Then
                'adjust for vertical and horz lines
                If Math.Abs(lslope) < 1 Then
                    'check pt between endpoints
                    'need this for multiple short lines end to end 
                    If ldx1 - (tolerance / 4) < Pt.X And ldx2 + (tolerance / 4) > Pt.X Then
                        If d2 < minDistance Then
                            minDistance = d2
                        End If
                    End If
                Else
                    If ldy1 > ldy2 Then
                        If ldy1 + (tolerance / 4) > Pt.Y And ldy2 - (tolerance / 4) < Pt.Y Then
                            'between ends so ok
                            If d2 < minDistance Then
                                minDistance = d2
                            End If
                        End If
                    Else
                        If ldy1 - (tolerance / 4) < Pt.Y And ldy2 + (tolerance / 4) > Pt.Y Then
                            If d2 < minDistance Then
                                minDistance = d2
                            End If
                        End If
                    End If
                End If
            End If
    
            Return minDistance
    
        End Function
    
        Public Function CheckZero(ByVal czvalue As Double) As Double
            If czvalue = 0 Then CheckZero = 0.000000000001 Else CheckZero = czvalue
        End Function
    
        Public Sub TOMSWAP(ByRef t1 As Double, ByRef t2 As Double)
            Dim t As Double
            t = t1
            t1 = t2
            t2 = t
        End Sub
    End Class
    
    

    • Marked as answer by Hany Metry Monday, November 25, 2019 4:35 AM
    Monday, November 25, 2019 4:14 AM
  • I need to be honest, the most drawing I do is coloring rich text box font.

    I'm guessing you cannot select a line you have drawn.

    I would:

    1. Get the coordinates of the click
    2. Determine if it is on the line
    3. Create x1, y1, and x2, y2
    4. Add highlight line

    George Frias - AWWshop @: Wikidot, GitHub

    Monday, November 25, 2019 4:39 AM
  • I really dont follow what you did with your last thread with the "line intersecting" or why but it sort of looks like you ran off the tracks into the cactus patch? I guess you know why you did what you did. :)


    Hi Mr. Tommy,

    Thank you very much Mr Tommy, you really brilliant

    I use line intersection for zoom because the graphics is unknown and its drawn function of picture box dimension bounds, so if you zoom a line dimension = 90% of picture box width (0.90 W) then the line still of dimension 0.90 W and you can't draw part of line but if the dimension of line = 900 pixel and the dimension of width of picture box = 1000 then you can draw part of the line in the zoom and the remaining of the line will be out of picture box view.

    The problem is that dimension of lines = 0.90 picture box width or height and I cant transfer it to fixed pixel dimension because the shape not drawn by mouse. (shape is unknown before draw).

    Kind Regards,


    Hany Metry


    • Edited by Hany Metry Monday, November 25, 2019 4:57 AM
    Monday, November 25, 2019 4:55 AM
  • Hi Tommy,

    Then how to delete your selection or modify it.

    Kind Regards,


    Hany Metry

    Monday, November 25, 2019 5:25 AM
  • Hi Mr. Tommy,

    Any how, I will try to input the shape by mouse and modify it at next version of my application after may be 5 months.

    And I marked your post as an answer even I will try to understand it after 5 months.

    Kind Regards,



    Hany Metry

    Monday, November 25, 2019 6:04 AM
  • Hi Mr. Tommy,

    Any how, I will try to input the shape by mouse and modify it at next version of my application after may be 5 months.

    And I marked your post as an answer even I will try to understand it after 5 months.

    Kind Regards,



    Hany Metry

    Hi Mr. Tommy,

    If I will success to input and modify the shape and reinforcement by mouse, then I will issue version of the program for that, but If I fail to have a good handy program for modify and input the shape and reinforcement by mouse, then I will not issue version for that.

    I will try to understand and practice and maybe i will ask other questions after one month.

    I am asking god to help me.

    God with me.

    Kind Regards,


    Hany Metry

    Monday, November 25, 2019 9:07 AM
  • Hi Tommy,

    Then how to delete your selection or modify it.

    Kind Regards,


    Hany Metry

    https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.remove?view=netframework-4.8
    Monday, November 25, 2019 11:57 AM