Zoom To Point не работает, как ожидалось - PullRequest
2 голосов
/ 16 августа 2010

Я пытаюсь реализовать в 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);
    }

}

Таким образом, важной частью является, очевидно, аффинное преобразование . Я знаю, что это в Adobe Flex, но у меня появилась идея Translate, Scale, Translate с этого сайта (отличный пример того, что я пытаюсь сделать). Я не осознавал, что MatrixOrder.Append был ключом в .NET, пока не попробовал. Но проблема все еще остается. Попробуйте загрузить элемент управления в приложение WinForms, и вы поймете, что я имею в виду. Кто-нибудь знает, в чем проблема с этим?

РЕДАКТИРОВАТЬ : причина, по которой мне нужно вручную вычислить прямоугольник, заключается в том, что я собираюсь нарисовать больше , чем просто изображение. Это холст, который работает как Visio. Мне также понадобится метод для преобразования определенного Point.

РЕДАКТИРОВАТЬ 2 : Я понимаю, что могу использовать Invert() на Matrix, а затем TransformPoints(), чтобы получить правильную трансформированную точку, но это все еще не решает проблему шаткого движения мышью , Я думал о вычислении Origin из местоположения верхнего угла изображения, но это не сработало.

1 Ответ

3 голосов
/ 17 августа 2010

Ах-ха!Я нашел это!Проанализировав ссылку, которую я разместил, я понял: «Эй, он нигде не устанавливает« масштабирование ». Затем я обнаружил проблему. Я каждый раз создавал новый 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...