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 ?
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();
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.
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]
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.
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
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
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
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
quangnp
Member
2 Points
1 Post
Re: matrix Pan and Zoom
Jan 26, 2009 06:09 PM | LINK