根据当前鼠标位置缩放图形
Posted
技术标签:
【中文标题】根据当前鼠标位置缩放图形【英文标题】:Zooming graphics based on current mouse position 【发布时间】:2016-09-12 17:40:46 【问题描述】:我正在尝试根据鼠标的当前位置缩放绘图。现在我的 onMouseWheel 方法看起来像这样(基于this *** 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 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);
【问题讨论】:
你能上传你的示例应用程序的代码吗?我认为这与您的规模有关,如果您使用_scale += 0.25f
而不是乘法,它是否有效。虽然这只是一个猜测,因为我现在没有一个可行的例子。
我添加了一个示例面板类,您可以将其添加到表单中。添加不起作用。如果我缩小太多,那会使缩放变为负数。这与翻译有关。缩放效果很好。
【参考方案1】:
懒得让方程式正确(而且很可能会犯和你类似的错误......我不知道这是否只是我,但正是这些简单的东西我无法处理并让我发疯)。相反,我正在按如下方式处理此类任务(这样更安全):
在屏幕坐标和世界坐标之间创建变换函数
所以你的鼠标位置在屏幕坐标中,渲染的东西在世界坐标中。因为这只是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;
缩放/比例变化
这个想法是,在缩放/缩放更改后,鼠标位置在世界坐标中应该与以前一样。所以在改变之前记住鼠标的世界坐标。然后根据它计算改变后的屏幕位置和翻译后的差异。
这里是简单的 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;
//---------------------------------------------------------------------------
【讨论】:
当我使用你的代码时它会做同样的事情。你测试过这个吗?如果有,能否提供全班的代码? 你在#2 下的方程似乎和我的方程做同样的事情。 _scale 最终被取消,你最终乘以 1.25。会不会是Graphics坐标和鼠标坐标原点不一样? @NathanBierema 是的,我在写它的时候犯了一个错误......(我之前做过很多次......)早上很着急。请参阅添加了功能源代码(来自 VCL,但您可以简单地将其移植到您的代码中)与我的想法。如果即使这也不起作用,那么您的鼠标坐标错误(不是相对于您的应用程序而是相对于桌面) @NathanBierema 添加了更好的捕获 GIF,所以你会发现这真的很管用,我用了好久... 好的,它仍然无法使用该代码。我的鼠标坐标似乎大致正确,因为如果我在 (100, 100) 处绘制一些东西并单击它,e.X 和 e.Y 在 (100, 100) 的一个像素内(我的鼠标可能偏离了几个像素)。如何计算相对于 Graphics 对象的鼠标坐标?以上是关于根据当前鼠标位置缩放图形的主要内容,如果未能解决你的问题,请参考以下文章