title: How to Mouse Hittest using IsVisible with rotated and transformed paths
body: <p>I am drawing scaleable vector graphics with GDI+ and I need to hitttest on mousemove. All the examples I've seen use model space = world space, with no transforms. Here's a simplified example of the problem:</p>
  
  <pre class="lang-vb prettyprint-override"><code>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 " &amp; e.Location.ToString)
      End If
  
    End Sub
  
  End Class
  </code></pre>
  
  <p>Which produces (mouse moving in red)
  <img src="https://i.stack.imgur.com/0SeIn.jpg" alt="enter image description here"></p>
  
  <p>IsVisible kicks in near the origin, where the rectangle was <strong>before</strong> the transforms.</p>
  
  <p>I know that if I had the Graphics used in OnPaint, I could use it to hittest with the transforms, but the golden rule says "never save graphics".</p>
  
  <p>Any suggestions would be most welcome.</p>
  
  <hr>
  
  <p>Post mortem: For the record, here's the implementation of Vincent's answer, which works nicely:</p>
  
  <pre class="lang-vb prettyprint-override"><code>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 " &amp; e.Location.ToString)
      End If
  
    End Sub
  
  End Class
  </code></pre>