Question

Im craeating a dart scoring program (to use myself in my dart room) and want the user to be able to click in different areas of a picture of a dart board to register the thrown darts.

This program will be resizable, so the picture of the dart board can change it's size when the user change the program window size.

Im using a list of polygons(pointF-arrays) to map up each area and run some calculation to see if the mouse click is inside the polygons area, but how do I scale those polygons correctly when the picturebox is resized? My polygons are hard coded to map the dartboards area of the picture at a specific size.

enter image description here

Edit: After the the really brilliant answer from Olivier Jacot-Descombes, I fixed the scaling with a GetScaledPoint-function that transform the mousepointer x and y value to values matching the original picture size, making it easy to check for hits in the original polygons. I have edited in the solution in the code below if anyone is interrested. In this example, Picture1 is a picture of a dart board (like this one http://quizmasters.biz/Pub%20Genius/Darts/Gfx/Dartboard_05.jpg) that is set to sizemode=stretch and docking=fill.

Public Class DartBoard
    Dim Double20 = New PointF() {New PointF(263, 78), New PointF(275, 76), New PointF(284, 76), New PointF(293, 75), New PointF(306, 75), New PointF(319, 75), New PointF(332, 76), New PointF(330, 89), New PointF(320, 88), New PointF(309, 87), New PointF(300, 87), New PointF(289, 88), New PointF(277, 89), New PointF(267, 91), New PointF(264, 78)}
    Dim Triple20 = New PointF() {New PointF(279, 154), New PointF(285, 154), New PointF(293, 154), New PointF(301, 152), New PointF(306, 152), New PointF(312, 152), New PointF(314, 151), New PointF(322, 152), New PointF(320, 167), New PointF(312, 165), New PointF(304, 164), New PointF(297, 165), New PointF(289, 166), New PointF(281, 166), New PointF(277, 154), New PointF(283, 153), New PointF(291, 153), New PointF(299, 152), New PointF(308, 152), New PointF(314, 153), New PointF(322, 153)}

    Private startwidth As Integer = 0
    Private startheight As Integer = 0
    Public Structure DartBoardAreaStruct
        Public Points As Integer
        Public Area() As PointF
    End Structure

    Dim DartBoardAreas As New List(Of DartBoardAreaStruct)

    Private Sub DartBoard_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        DartBoardAreas.Add(New DartBoardAreaStruct With {.Area = Double20, .Points = 40})
        DartBoardAreas.Add(New DartBoardAreaStruct With {.Area = Triple20, .Points = 60})

        startwidth = PictureBox1.Width
        startheight = PictureBox1.Height

    End Sub
    Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
        Dim scaledpos As PointF = GetScaledPoint(e.Location)
        For Each DartBoardArea In DartBoardAreas
            If Me.PolyGonHitTest(DartBoardArea.Area, scaledpos) Then
                MsgBox(DartBoardArea.Points)
            End If
        Next
    End Sub

    Public Function PolyGonHitTest(ByVal polygonPoints() As PointF, ByVal mousePos As PointF) As Boolean

        Dim path As New System.Drawing.Drawing2D.GraphicsPath
        path.AddLines(polygonPoints)
        Dim region As New Region(path)
        If region.IsVisible(mousePos) Then Return True
        Return False
    End Function

    Function GetScaledPoint(ByVal s As Point) As PointF
        Dim xfactor As Double = 0
        Dim yfactor As Double = 0

        Dim OriginalSize As Size = New Size(startwidth, startheight)
        Dim NewSize As Size = New Size(PictureBox1.Width, PictureBox1.Height)

        If NewSize.Width < OriginalSize.Width Then
            xfactor = OriginalSize.Width / NewSize.Width
        Else
            xfactor = NewSize.Width / OriginalSize.Width
        End If
        If NewSize.Height < OriginalSize.Height Then
            yfactor = OriginalSize.Height / NewSize.Height
        Else
            yfactor = NewSize.Height / OriginalSize.Height
        End If
        Return New PointF(s.X / xfactor, s.Y / yfactor)
    End Function
End Class
Was it helpful?

Solution

A easy and fast solution would be to keep the polygons unchanged, but to scale the mouse coordinates. For instance you could have polygon coordiantes between 0.0f and 1.0f and scale your mouse coordinates like:

xScaled As Single = e.X/DartBoardArea.Width
yScaled As Single = e.Y/DartBoardArea.Height
scaledPos As PointF = new PointF(xScaled, yScaled)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top