title: Zoom To Point Not Working As Expected
body: <p>I'm trying to implement a simple "zoom to point" functionality in WinForms. When the mouse is at the same point and the mouse wheel is scrolled in/out, it works great. When the mouse position is <em>changed</em> between scrolls, it jumps to that position and is very wonky. Here's the code for the control that you can add to a <code>Form</code> for testing:</p>
  
  <pre><code>public class Canvas : Control
  {
  
      private Bitmap Image;
      private TextureBrush ImageBrush;
      private Point Origin;
      private Matrix TransformMatrix;
  
      public float ZoomScale
      {
          get;
          set;
      }
  
      public Canvas()
      {
          this.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
  
          this.Image = // Load your picture here.
          this.ImageBrush = new TextureBrush(this.Image, WrapMode.Clamp);
          this.ZoomScale = 1.0f;
  
          this.TransformMatrix = new Matrix();
  
      }
  
      protected override void OnPaint(PaintEventArgs e)
      {
          float zs = this.ZoomScale;
  
          var matrix = this.TransformMatrix.Clone();
          e.Graphics.Transform = matrix;
  
          var c = e.ClipRectangle;
  
          // Transform the clip rectangle, is this even right?
          var x = (int)Math.Round(c.X / zs - matrix.OffsetX / zs);
          var y = (int)Math.Round(c.Y / zs - matrix.OffsetY / zs);
          var w = (int)Math.Round(c.Width / zs);
          var h = (int)Math.Round(c.Height / zs);
  
          // Draw the image scaled and translated.
          e.Graphics.FillRectangle(this.ImageBrush, x, y, w - 1, h - 1);
  
      }
  
      protected override void OnMouseWheel(MouseEventArgs e)
      {
          if (e.Delta &gt; 0)
          {
              this.ZoomScale += 0.1f;
          }
          else
          {
              this.ZoomScale -= 0.1f;
          }
  
          this.ZoomToPoint(e.Location);
          this.Refresh();
      }
  
      private void ZoomToPoint(Point origin)
      {
          this.Origin = origin;
          float zoomScale = this.ZoomScale;
  
          // The important part.
          var matrix = new Matrix(1, 0, 0, 1, 0, 0);
          matrix.Reset();
          matrix.Translate(-origin.X, -origin.Y, MatrixOrder.Append);
          matrix.Scale(zoomScale, zoomScale, MatrixOrder.Append);
          matrix.Translate(origin.X, origin.Y, MatrixOrder.Append);
          this.TransformMatrix = matrix;
      }
  
      protected override void OnResize(EventArgs e)
      {
          base.OnResize(e);
          this.ZoomToPoint(this.Origin);
      }
  
  }
  </code></pre>
  
  <p>So the important part is obviously the <a href="http://en.wikipedia.org/wiki/Affine_transformation" rel="nofollow noreferrer">affine transformation</a>. I know it's in Adobe Flex, but I got the idea of <code>Translate</code>, <code>Scale</code>, <code>Translate</code> from <a href="http://gasi.ch/blog/zooming-in-flash-flex/" rel="nofollow noreferrer">this website</a> (great example of what I'm trying to do). I didn't realize that <code>MatrixOrder.Append</code> was the key in <code>.NET</code> until I tried. But the problem still remains. Try loading the control in a WinForms application and you'll see what I mean. Does anyone know what the issue is with this?</p>
  
  <p><strong>EDIT</strong>: The reason I need to <em>manually</em> calculate the rectangle is because I'm going to be drawing <em>more</em> than just an image. It's a canvas that performs like Visio. I'll also need a method for transforming a specific <code>Point</code>.</p>
  
  <p><strong>EDIT 2</strong>: I understand that I can use <code>Invert()</code> on the <code>Matrix</code> then <code>TransformPoints()</code> to get a proper transformed point but it still doesn't solve the problem of the wonky mouse movement. I was thinking of calculating the <code>Origin</code> from the location of the top corner of the image but it didn't work.</p>