根据当前鼠标位置缩放图形

我正在尝试根据鼠标的当前位置缩放绘图。 现在我的onMouseWheel方法看起来像这样(基于这个StackOverflow答案 ):

private void onMouseWheel(object sender, MouseEventArgs e) { if (e.Delta > 0) { _scale *= 1.25f; _translateY = eY - 1.25f * (eY - _translateY); _translateX = eX - 1.25f * (eX - _translateX); } else { _scale /= 1.25f; _translateY = eY - 0.8f * (eY - _translateY); _translateX = eX - 0.8f * (eX - _translateX); } this.Invalidate(); } 

_scale_translateX_translateY是成员变量。

我正在缩放图形,翻译图形,然后绘制这样的线条:

  protected override void OnPaint(PaintEventArgs e) { g.ScaleTransform(_scale, _scale); g.TranslateTransform(_translateX, _translateY); //draw lines here } 

此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 = eY - 1.25f * (eY - _translateY); _translateX = eX - 1.25f * (eX - _translateX); } else { _scale /= 1.25f; _translateY = eY - 0.8f * (eY - _translateY); _translateX = eX - 0.8f * (eX - _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); } } 

懒得让方程式正确(而且很可能会出现类似的错误……我不知道它是否仅仅是我,但正是这些简单的东西我无法处理并让我发疯)。 相反,我正在处理以下这类任务(从错误中更安全):

  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; 
  2. 缩放/缩放的变化

    我们的想法是,在缩放/缩放后,鼠标位置应保持与以前一样的世界坐标。 所以记住改变之前鼠标的世界坐标。 然后从中计算出更改后的屏幕位置和转换后的差异。

这里简单的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; } //---------------------------------------------------------------------------