缩放到点不按预期工作

我正在尝试在WinForms中实现一个简单的“缩放到点”function。 当鼠标位于同一点并且鼠标滚轮滚入/滚出时,效果很好。 当滚动之间的鼠标位置发生变化时 ,它会跳到该位置并且非常不稳定。 以下是可以添加到Form以进行测试的控件代码:

 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(cX / zs - matrix.OffsetX / zs); var y = (int)Math.Round(cY / 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 > 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); } } 

因此,重要的部分显然是仿射变换 。 我知道它是在Adobe Flex中,但我从这个网站得到了TranslateScaleTranslate的想法(我正在尝试做的很好的例子)。 在我尝试之前,我没有意识到MatrixOrder.Append.NET中的关键。 但问题仍然存在。 尝试在WinForms应用程序中加载控件,你会明白我的意思。 有谁知道这个问题是什么?

编辑 :我需要手动计算矩形的原因是因为我将绘制的不仅仅是图像。 它是一个像Visio一样执行的canvas。 我还需要一种转换特定Point

编辑2 :我知道我可以在Matrix上使用Invert()然后使用TransformPoints()来获得正确的变换点,但它仍然无法解决鼠标移动的问题。 我正在考虑从图像顶角的位置计算Origin ,但它不起作用。

啊,哈! 我找到了! 在分析了我发布的链接后,我意识到“嘿,他没有在任何地方设置”缩放比例“。然后我发现了问题。我每次都在创建一个新的Matrix 。这不是正确的方法。它应该扩展/翻译当前的转换:

 private void ZoomToPoint(float scale, Point origin) { var matrix = this.TransformMatrix; matrix.Translate(-origin.X, -origin.Y, MatrixOrder.Append); matrix.Scale(scale, scale, MatrixOrder.Append); matrix.Translate(origin.X, origin.Y, MatrixOrder.Append); this.TransformMatrix = matrix; } 

对此的呼吁如下:

 // Zoom in this.ZoomToPoint(6 / 5.0f, e.Location); 

 // Zoom out this.ZoomToPoint(5 / 6.0f, e.Location);