Powered by MSDN

US - English
NEW! Silverlight 5 is available Learn More

matrix Pan and Zoom RSS

4 replies

Last post Jan 26, 2009 06:09 PM by quangnp

(0)
  • silverlightOnly

    silverlightOnly

    Member

    20 Points

    12 Posts

    matrix Pan and Zoom

    Nov 19, 2008 06:03 PM | LINK

    Discovered a strange translation occurring on centered zoom (zoom<>1) after a pan.
    The goal is to zoom always on a constant point of the screen, presented by a red circle. Pan is controlled with arrow keys, zoom - with key plus(+) or minus(-).
    Everything works fine, except when scaling with zoom <>1 after a pan. Cannot figure out where this one-time translation comes from... Before and after this event panning and zooming work as expected.
    Here is the code. What am I missing ?

     <UserControl x:Class="ZoPanNS.ZoPan"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="600" Height="600">
        <Canvas Background="White">
            <Ellipse Canvas.Left="200" Canvas.Top="200" Canvas.ZIndex="2"
                    Width="12" Height="12" Stroke="Red" StrokeThickness="2" Fill="Transparent" />
            <TextBlock x:Name="TxtB" Canvas.Left="0" Canvas.Top="0" Canvas.ZIndex="2"
                    Width="200" Height="20" Text="click here to start" />
            
            <Canvas x:Name="cMoved" Background="PaleGreen" Canvas.Left="100" Canvas.Top="100"
                    Width="200" Height="200" RenderTransformOrigin="0,0">
                <Rectangle Canvas.Left="0" Canvas.Top="0"
                    Width="200" Height="200" Stroke="DarkCyan" StrokeThickness="2" Fill="Wheat" />
                <Ellipse x:Name="Ccircle" Canvas.Left="100" Canvas.Top="100"
                    Width="7" Height="7" Stroke="Green" StrokeThickness="2" Fill="Green" />
            </Canvas>
        </Canvas>
    </UserControl>

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Shapes;

    namespace ZoPanNS
    {
        public partial class ZoPan : UserControl
        {
            double Xstep = 40, Ystep = 40, Zstep = 0.2;
            double CenterX=100, CenterY=100;
            private MatrixTransform _matrixTransform = new MatrixTransform();

            public ZoPan()
            {
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(Page_Loaded);
            }
            private void Page_Loaded(object o, EventArgs e)
            {
                cMoved.RenderTransform = _matrixTransform;
                cMoved.RenderTransformOrigin = new Point(.5, .5); //center
                this.KeyDown += new KeyEventHandler(page_KeyDown);
            }
            private void page_KeyDown(object sender, KeyEventArgs e)
            {
                Matrix matrix = _matrixTransform.Matrix;
                switch (e.Key)
                {
                    case Key.Left:
                        CenterX += Xstep;
                        Ccircle.SetValue(Canvas.LeftProperty, CenterX);
                        matrix.OffsetX -= Xstep * matrix.M11;
                        break;
                    case Key.Right:
                        CenterX -= Xstep;
                        Ccircle.SetValue(Canvas.LeftProperty, CenterX);
                        matrix.OffsetX += Xstep * matrix.M11;
                        break;
                    case Key.Up:
                        CenterY += Ystep;
                        Ccircle.SetValue(Canvas.TopProperty, CenterY);
                        matrix.OffsetY -= Ystep * matrix.M22;
                        break;
                    case Key.Down:
                        CenterY -= Ystep;
                        Ccircle.SetValue(Canvas.TopProperty, CenterY);
                        matrix.OffsetY += Ystep * matrix.M22;
                        break;

                    case Key.Add:
                        matrix.M11 += Zstep;
                        matrix.M22 = matrix.M11;
                        cMoved.RenderTransformOrigin = new Point(
                            CenterX / cMoved.ActualWidth, CenterY / cMoved.ActualHeight);
                        break;

                    case Key.Subtract:
                        matrix.M11 -= Zstep;
                        matrix.M22 = matrix.M11;
                        cMoved.RenderTransformOrigin = new Point(
                            CenterX / cMoved.ActualWidth, CenterY / cMoved.ActualHeight);
                        break;
                    default:
                        return;
                }
                _matrixTransform.Matrix = matrix;
                TxtB.Text = "zoom=" + matrix.M11.ToString("0.0")
                    + " cX=" + CenterX.ToString("0.0")
                    + " oX=" + matrix.OffsetX.ToString("0.0")
                    + " rX=" + cMoved.RenderTransformOrigin.X.ToString("0.0")
                ;
            }
        }
    }

    RenderTransformOrigin Silverlight 2 Pan and zoom

  • StefanWick

    StefanWick

    Contributor

    3004 Points

    453 Posts

    Microsoft

    Re: matrix Pan and Zoom

    Dec 06, 2008 06:04 AM | LINK

    I think your math is slightly off because you are using CenterX/Y for two different things: (a) to position the Circle and (b) to determine the center of rotation.

    Note that the position (Canvas.Left/Top) of the Ellipse refers to the upper left corner of its bounding rectangle - not to its center, hence the translation.

    Thanks, Stefan Wick

    Microsoft Silverlight | http://blogs.msdn.com/swick/
  • silverlightOnly

    silverlightOnly

    Member

    20 Points

    12 Posts

    Re: matrix Pan and Zoom

    Dec 07, 2008 12:29 AM | LINK

    Yes - "using CenterX/Y for two different things: (a) to position the Circle and (b) to determine the center of scaling" - what is wrong with that ?
    Yes - "(Canvas.Left/Top) of the Ellipse refers to the upper left corner of its bounding rectangle - not to its center" - but these couple of pixels are not part of the problem.

    Here is how to reproduce the translation:
    The program starts with a yellow square with a green and red circles in the middle. Click on the page to begin. Hit the Up-arrow key twice to pan the square, then + key four times to zoom it. So far so good - pan and zoom are working ok. Now hit the Down-arrow key four times, then the + key once - and watch the translation happen. If you continue zooming with + or -, the square is correctly scaled with the green circle as center. But the green and red circle are not aligned anymore.
    The goal is to have these two aligned at all times with every zoom centered at them. In other words - have a constant zoom center on the screen regardless of pan operations.
    If someone can present a code to do this simple task, I promise to retire humbly, not to be seen again [H]

  • StefanWick

    StefanWick

    Contributor

    3004 Points

    453 Posts

    Microsoft

    Re: matrix Pan and Zoom

    Dec 07, 2008 05:42 AM | LINK

    I fixed up your sample and uploaded the working version here (source code is attached to the post). The task gets a lot easier (at least my mind) when you seperate out the Scale vs. Translate transforms.

    http://blogs.msdn.com/swick/pages/pan-zoom-example.aspx

    (note that I have changed the keys to use PageUp/Down since that was easier on my keyboard :-))

    Thanks, Stefan Wick

    Microsoft Silverlight | http://blogs.msdn.com/swick/
  • quangnp

    quangnp

    Member

    2 Points

    1 Post

    Re: matrix Pan and Zoom

    Jan 26, 2009 06:09 PM | LINK

    I want to create zoom and pan system that all shape stroke always is 1 pixel width (hairline). Do you have any idea?