根据当前鼠标位置缩放图形
Zooming graphics based on current mouse position
我正在尝试根据鼠标的当前位置缩放绘图。现在我的 onMouseWheel 方法看起来像这样(基于 this Whosebug answer):
private void onMouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0)
{
_scale *= 1.25f;
_translateY = e.Y - 1.25f * (e.Y - _translateY);
_translateX = e.X - 1.25f * (e.X - _translateX);
}
else
{
_scale /= 1.25f;
_translateY = e.Y - 0.8f * (e.Y - _translateY);
_translateX = e.X - 0.8f * (e.X - _translateX);
}
this.Invalidate();
}
_scale
、_translateX
、_translateY
是成员变量。
我正在缩放图形,翻译它,然后像这样画线:
protected override void OnPaint(PaintEventArgs e)
{
g.ScaleTransform(_scale, _scale);
g.TranslateTransform(_translateX, _translateY);
//draw lines here
}
This video 显示当我尝试放大和缩小某个点时发生的情况。我做错了什么?
出于测试目的,示例面板 class 中的代码如下所示:
class Display : Panel
{
public Display()
{
this.MouseWheel += new MouseEventHandler(this.onMouseWheel);
}
private void onMouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0)
{
_scale *= 1.25f;
_translateY = e.Y - 1.25f * (e.Y - _translateY);
_translateX = e.X - 1.25f * (e.X - _translateX);
}
else
{
_scale /= 1.25f;
_translateY = e.Y - 0.8f * (e.Y - _translateY);
_translateX = e.X - 0.8f * (e.X - _translateX);
}
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
g.ScaleTransform(_scale, _scale);
g.TranslateTransform(_translateX, _translateY);
Pen pen = new Pen(Color.Red);
g.FillEllipse(pen.Brush, 50, 50, 10, 10);
}
}
懒得把方程式弄对(而且很可能会犯和你一样的错误……我不知道是不是只有我一个人,但正是这些简单的事情我无法处理,让我发疯)。相反,我按如下方式处理此类任务(这样更安全,不会出错):
创建屏幕坐标和世界坐标之间的变换函数
所以你的鼠标位置在屏幕坐标中,渲染的东西在世界坐标中。因为这只是 2D 所以很容易。 make 在这两者之间进行转换的函数。你的屏幕转换世界(如果我没有忽略某些东西)是这样的:
g.ScaleTransform(_scale, _scale);
g.TranslateTransform(_translateX, _translateY);
所以:
screen_x=(world_x*_scale)+_translateX;
screen_y=(world_y*_scale)+_translateY;
所以反过来:
world_x=(screen_x-_translateX)/_scale;
world_y=(screen_y-_translateY)/_scale;
zoom/scale
的变化
想法是,在 zoom/scale 更改后,鼠标位置在世界坐标中应与以前保持相同。所以在改变之前记住鼠标的世界坐标。然后从中计算出变化后的屏幕位置和平移的差异。
这里是简单的C++例子:
double x0=0.0,y0=0.0,zoom=1.0,mx,my;
//---------------------------------------------------------------------------
void scr2obj(double &ox,double &oy,double sx,double sy)
{
ox=(sx-x0)/zoom;
oy=(sy-y0)/zoom;
}
//---------------------------------------------------------------------------
void obj2scr(double &sx,double &sy,double ox,double oy)
{
sx=x0+(ox*zoom);
sy=y0+(oy*zoom);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom/=1.25; // zoom out
obj2scr(mx0,my0,mx0,my0);
x0+=mx-mx0;
y0+=my-my0;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom*=1.25; // zoom in
obj2scr(mx0,my0,mx0,my0);
x0+=mx-mx0;
y0+=my-my0;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X,int Y)
{
mx=X; my=Y;
}
//---------------------------------------------------------------------------
mx,my
是屏幕坐标中的实际鼠标位置,x0,y0
是平移,zoom
是比例。
这里捕获了 GIF 动画:
[edit1] 看起来你的 gfx 对象使用转置矩阵
这意味着转换的顺序被颠倒了,所以方程式发生了一点变化...这里是 C++:
中的案例示例
void scr2obj(double &ox,double &oy,double sx,double sy)
{
// ox=(sx-x0)/zoom;
// oy=(sy-y0)/zoom;
ox=(sx/zoom)-x0;
oy=(sy/zoom)-y0;
}
//---------------------------------------------------------------------------
void obj2scr(double &sx,double &sy,double ox,double oy)
{
// sx=x0+(ox*zoom);
// sy=y0+(oy*zoom);
sx=(x0+ox)*zoom;
sy=(y0+oy)*zoom;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom/=1.25; // zoom out
obj2scr(mx0,my0,mx0,my0);
// x0+=mx-mx0;
// y0+=my-my0;
x0+=(mx-mx0)/zoom;
y0+=(my-my0)/zoom;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom*=1.25; // zoom in
obj2scr(mx0,my0,mx0,my0);
// x0+=mx-mx0;
// y0+=my-my0;
x0+=(mx-mx0)/zoom;
y0+=(my-my0)/zoom;
_redraw=true;
}
//---------------------------------------------------------------------------
我正在尝试根据鼠标的当前位置缩放绘图。现在我的 onMouseWheel 方法看起来像这样(基于 this Whosebug answer):
private void onMouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0)
{
_scale *= 1.25f;
_translateY = e.Y - 1.25f * (e.Y - _translateY);
_translateX = e.X - 1.25f * (e.X - _translateX);
}
else
{
_scale /= 1.25f;
_translateY = e.Y - 0.8f * (e.Y - _translateY);
_translateX = e.X - 0.8f * (e.X - _translateX);
}
this.Invalidate();
}
_scale
、_translateX
、_translateY
是成员变量。
我正在缩放图形,翻译它,然后像这样画线:
protected override void OnPaint(PaintEventArgs e)
{
g.ScaleTransform(_scale, _scale);
g.TranslateTransform(_translateX, _translateY);
//draw lines here
}
This video 显示当我尝试放大和缩小某个点时发生的情况。我做错了什么?
出于测试目的,示例面板 class 中的代码如下所示:
class Display : Panel
{
public Display()
{
this.MouseWheel += new MouseEventHandler(this.onMouseWheel);
}
private void onMouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0)
{
_scale *= 1.25f;
_translateY = e.Y - 1.25f * (e.Y - _translateY);
_translateX = e.X - 1.25f * (e.X - _translateX);
}
else
{
_scale /= 1.25f;
_translateY = e.Y - 0.8f * (e.Y - _translateY);
_translateX = e.X - 0.8f * (e.X - _translateX);
}
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
g.ScaleTransform(_scale, _scale);
g.TranslateTransform(_translateX, _translateY);
Pen pen = new Pen(Color.Red);
g.FillEllipse(pen.Brush, 50, 50, 10, 10);
}
}
懒得把方程式弄对(而且很可能会犯和你一样的错误……我不知道是不是只有我一个人,但正是这些简单的事情我无法处理,让我发疯)。相反,我按如下方式处理此类任务(这样更安全,不会出错):
创建屏幕坐标和世界坐标之间的变换函数
所以你的鼠标位置在屏幕坐标中,渲染的东西在世界坐标中。因为这只是 2D 所以很容易。 make 在这两者之间进行转换的函数。你的屏幕转换世界(如果我没有忽略某些东西)是这样的:
g.ScaleTransform(_scale, _scale); g.TranslateTransform(_translateX, _translateY);
所以:
screen_x=(world_x*_scale)+_translateX; screen_y=(world_y*_scale)+_translateY;
所以反过来:
world_x=(screen_x-_translateX)/_scale; world_y=(screen_y-_translateY)/_scale;
zoom/scale
的变化想法是,在 zoom/scale 更改后,鼠标位置在世界坐标中应与以前保持相同。所以在改变之前记住鼠标的世界坐标。然后从中计算出变化后的屏幕位置和平移的差异。
这里是简单的C++例子:
double x0=0.0,y0=0.0,zoom=1.0,mx,my;
//---------------------------------------------------------------------------
void scr2obj(double &ox,double &oy,double sx,double sy)
{
ox=(sx-x0)/zoom;
oy=(sy-y0)/zoom;
}
//---------------------------------------------------------------------------
void obj2scr(double &sx,double &sy,double ox,double oy)
{
sx=x0+(ox*zoom);
sy=y0+(oy*zoom);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom/=1.25; // zoom out
obj2scr(mx0,my0,mx0,my0);
x0+=mx-mx0;
y0+=my-my0;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom*=1.25; // zoom in
obj2scr(mx0,my0,mx0,my0);
x0+=mx-mx0;
y0+=my-my0;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X,int Y)
{
mx=X; my=Y;
}
//---------------------------------------------------------------------------
mx,my
是屏幕坐标中的实际鼠标位置,x0,y0
是平移,zoom
是比例。
这里捕获了 GIF 动画:
[edit1] 看起来你的 gfx 对象使用转置矩阵
这意味着转换的顺序被颠倒了,所以方程式发生了一点变化...这里是 C++:
中的案例示例void scr2obj(double &ox,double &oy,double sx,double sy)
{
// ox=(sx-x0)/zoom;
// oy=(sy-y0)/zoom;
ox=(sx/zoom)-x0;
oy=(sy/zoom)-y0;
}
//---------------------------------------------------------------------------
void obj2scr(double &sx,double &sy,double ox,double oy)
{
// sx=x0+(ox*zoom);
// sy=y0+(oy*zoom);
sx=(x0+ox)*zoom;
sy=(y0+oy)*zoom;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom/=1.25; // zoom out
obj2scr(mx0,my0,mx0,my0);
// x0+=mx-mx0;
// y0+=my-my0;
x0+=(mx-mx0)/zoom;
y0+=(my-my0)/zoom;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom*=1.25; // zoom in
obj2scr(mx0,my0,mx0,my0);
// x0+=mx-mx0;
// y0+=my-my0;
x0+=(mx-mx0)/zoom;
y0+=(my-my0)/zoom;
_redraw=true;
}
//---------------------------------------------------------------------------