代码之家  ›  专栏  ›  技术社区  ›  TheCloudlessSky

缩放到不按预期工作的点

  •  2
  • TheCloudlessSky  · 技术社区  · 15 年前

    我试图在WinForms中实现一个简单的“缩放到点”功能。当鼠标在同一个点上,鼠标滚轮被向内/向外滚动时,效果非常好。当鼠标位置 改变 在卷轴之间,它跳到那个位置,非常不稳定。下面是可以添加到 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(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 > 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);
        }
    
    }
    

    所以重要的部分显然是 affine transformation . 我知道它在adobeflex中,但是我想到了 Translate , Scale , 翻译 this website MatrixOrder.Append .NET 直到我试过。但问题仍然存在。尝试在WinForms应用程序中加载控件,您就会明白我的意思。有人知道这有什么问题吗?

    编辑 :我需要 手动 计算这个矩形是因为我要画画 更多 不仅仅是图像。这是一个画布,表现像视觉。我还需要一个方法来转换一个特定的 Point .

    编辑2 Invert() Matrix TransformPoints() Origin 从图像上角的位置,但它没有工作。

    1 回复  |  直到 15 年前
        1
  •  3
  •   TheCloudlessSky    15 年前

    啊哈!我找到了!在分析了我发布的链接后,我意识到“嘿,他没有在任何地方设置缩放比例。然后我发现了问题。我在创造一个新的 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);