2

我正在使用 GDI+ 绘制可缩放矢量图形,我需要在 mousemove 上进行测试。我见过的所有示例都使用模型空间 = 世界空间,没有变换。这是问题的简化示例:

Imports System.Drawing.Drawing2D

Public Class Form1

  Private myrect As New GraphicsPath

  Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

    ' The rectangle's centre is at 30,10. Move to origin to rotate
    e.Graphics.TranslateTransform(-30, -10, Drawing2D.MatrixOrder.Append)
    e.Graphics.RotateTransform(45, Drawing2D.MatrixOrder.Append)

    ' Move it back, 50x50 away from the origin 
    ' (80,60 because we moved -30,-10 to rotate)
    e.Graphics.TranslateTransform(80, 60, Drawing2D.MatrixOrder.Append)
    e.Graphics.DrawPath(New Pen(Brushes.Black, 2), myrect)

    ' ...loads more painting, many paths, many varying transformations

  End Sub

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Load

    ' Make a rectangle 60x20 with top-left corner at the origin
    myrect.AddLine(0, 0, 60, 0)
    myrect.AddLine(60, 0, 60, 20)
    myrect.AddLine(60, 20, 0, 20)
    myrect.CloseFigure()

    ' ...loads more shapes created here

  End Sub

  Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove

    ' Pretend that all the drawing stuff above happened some unspecified time ago, 
    ' in different assembly, written by a martian, in some other vile language.
    ' Obviously, his "e.graphics" has long since been garbage-collected.
    If myrect.IsVisible(e.Location) Then
        ' Works when moving over the path at the origin, ignores transforms.
        Debug.WriteLine("Over the rectangle at " & e.Location.ToString)
    End If

  End Sub

End Class

哪个产生(鼠标以红色移动) 在此处输入图像描述

IsVisible 在原点附近开始,矩形在变换之前。

我知道如果我有在 OnPaint 中使用的图形,我可以用它来测试变换,但黄金法则是“永远不要保存图形”。

任何建议都将受到欢迎。


验尸:为了记录,这是文森特答案的实现,效果很好:

Imports System.Drawing.Drawing2D

Public Class Form1

  Private myrect As New GraphicsPath
  Private mytransform As Matrix

  Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

    ' The rectangle's centre is at 30,10. Move to origin to rotate
    e.Graphics.TranslateTransform(-30, -10, Drawing2D.MatrixOrder.Append)
    e.Graphics.RotateTransform(45, Drawing2D.MatrixOrder.Append)

    ' Move it back, 50x50 away from the origin 
    ' (80,60 because we moved -30,-10 to rotate)
    e.Graphics.TranslateTransform(80, 60, Drawing2D.MatrixOrder.Append)
    e.Graphics.DrawPath(New Pen(Brushes.Black, 2), myrect)
    mytransform = e.Graphics.Transform

    ' ...loads more painting, many paths, many varying transformations

  End Sub

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Load

    ' Make a rectangle 60x20 with top-left corner at the origin
    myrect.AddLine(0, 0, 60, 0)
    myrect.AddLine(60, 0, 60, 20)
    myrect.AddLine(60, 20, 0, 20)
    myrect.CloseFigure()

    ' ...loads more shapes created here

  End Sub

  Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove

    mytransform.Invert()
    Dim mouseat() As Point = {e.Location}
    mytransform.TransformPoints(mouseat)
    If myrect.IsVisible(mouseat(0)) Then
        ' Works when moving over the path at the origin, ignores transforms.
        Debug.WriteLine("Over the rectangle at " & e.Location.ToString)
    End If

  End Sub

End Class
4

2 回答 2

3

ScaleTransform 和 TranslateTransform 方法更改 Graphics.Matrix 属性。您想保留它,将相同的变换应用于鼠标位置将非常方便。由于您将变换应用于单个形状,因此您希望存储每个形状的矩阵。

Matrix.TransformPoints() 然后解决您的问题。

于 2012-05-24T01:41:52.263 回答
2

保存图形对象的世界变换矩阵(Graphics.Transform),反转它(所以它从页面坐标到世界坐标 - 我认为在这种情况下页面坐标等于设备坐标,但如果不是,你将不得不做更多的工作考虑缩放),并在进行命中测试之前使用它来转换您的点。

编辑:您还可以将用于构建世界变换的 OnPaint 中的逻辑分解为不需要 Graphics 对象并返回 Matrix 的单独方法,然后您可以将其与 Graphics.MultiplyTransform 一起使用或反转并用于修改您的输入坐标。

于 2012-05-24T00:42:26.113 回答