Как масштабировать полигоны, сопоставленные с изменяемым размером изображения

Я создаю программу подсчета очков (чтобы использовать себя в своей комнате для игры в дартс) и хочу, чтобы пользователь мог щелкать в разных областях изображения доски для дартс, чтобы регистрировать брошенные дротики.

Размер этой программы можно изменять, поэтому изображение мишени для дартс может изменить свой размер, когда пользователь изменит размер окна программы.

Я использую список полигонов (массивы точек F), чтобы отобразить каждую область и выполнить некоторые вычисления, чтобы увидеть, находится ли щелчок мыши внутри области полигонов, но как мне правильно масштабировать эти полигоны при изменении размера окна изображения? Мои полигоны жестко закодированы для отображения области мишени для дротиков на изображении определенного размера.

введите здесь описание изображения

Редактировать: После действительно блестящего ответа от Olivier Jacot-Descombes я исправил масштабирование с помощью функции GetScaledPoint, которая преобразует значения x и y указателя мыши в значения, соответствующие исходному размеру изображения, что упрощает проверьте наличие попаданий в исходные полигоны. Я отредактировал решение в приведенном ниже коде, если кому-то интересно. В этом примере Picture1 — это изображение доски для дартс (например, http://quizmasters.biz/Pub%20Genius/Darts/Gfx/Dartboard_05.jpg), для которого установлено значение sizemode=stretch и doking=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

person Stefan    schedule 29.09.2011    source источник


Ответы (1)


Простым и быстрым решением было бы оставить полигоны без изменений, но масштабировать координаты мыши. Например, у вас могут быть координаты многоугольника между 0.0f и 1.0f и масштабировать координаты мыши следующим образом:

xScaled As Single = e.X/DartBoardArea.Width
yScaled As Single = e.Y/DartBoardArea.Height
scaledPos As PointF = new PointF(xScaled, yScaled)
person Olivier Jacot-Descombes    schedule 29.09.2011
comment
Великолепно! Просто масштабируйте положение мыши вместо всех полигонов. Простота в лучшем виде! Я использовал другую реализацию для масштабирования, чем в вашем примере, но это сработало как шарм! - person Stefan; 29.09.2011