2010-08-16 2 views
2

Я пытаюсь реализовать простую функциональность «масштабирования для точки» в WinForms. Когда мышь находится в одной точке и колесико мыши прокручивается в/из, оно отлично работает. Когда положение мыши изменено между свитками, оно перескакивает в эту позицию и очень неудобно. Вот код для элемента управления, который можно добавить к Form для тестирования:Zoom To Point Не работает как ожидается

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

EDIT: Причина мне нужно вручную вычислить прямоугольник, потому что я собираюсь быть рисунок более, чем просто изображение. Это холст, который работает как Visio. Мне также понадобится метод для преобразования определенного Point.

EDIT 2: Я понимаю, что я могу использовать Invert() на Matrix затем TransformPoints(), чтобы получить надлежащие преобразованные точки, но это еще не решает проблему шаткого движения мыши. Я думал о вычислении Origin из местоположения верхнего угла изображения, но он не работал.

ответ

3

Ah-ha! Я нашел это! После анализа ссылки, которую я опубликовал, я понял: «Эй, он не устанавливает« масштабную шкалу »где-нибудь, тогда я нашел проблему. Я создавал новый 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); 
+0

Ах bumme Я надеялся решить эту проблему. :) –

+0

@Carter - Да, как только я это увидел, у меня был «D'OH!». момент. – TheCloudlessSky