2016-05-16 41 views
3

我试图根据鼠标的当前位置缩放图形。现在我onMouseWheel方法如下所示(基于this StackOverflow 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); 
    } 
} 
+0

您可以上传示例应用程序的代码吗?我认为它与你的规模有关,如果你使用_scale + = 0.25f而不是乘法,它是否工作。虽然这只是一个猜测,因为我现在没有一个工作的例子。 – dwonisch

+0

我添加了一个示例面板类,您可以将其添加到表单中。添加不起作用。如果我缩小太多,这将使变焦变为负值。它与翻译有关。缩放工作正常。 –

回答

0

懒得做出正确的方程(最有可能会做出类似的错误,你......我不知道它是否只是我,但正是我不能处理这种简单的东西,让我发疯)。相反,我处理这类任务如下(这是从错误中更安全):

  1. 造屏和世界之间的转换函数坐标

    所以,你的鼠标的位置是在屏幕坐标和渲染的东西是在世界坐标。因为这只是2D那么这很容易。使这两个功能之间进行转换。你的世界到屏幕变换(如果我不是忽视的东西)是这样的:

    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. 变焦的变化/规模

    这个想法是,在变焦/ s cale更改鼠标位置应保持与以前一样的世界坐标。所以记住改变之前鼠标的世界坐标。然后从中计算出变化后的屏幕位置和差异。

这里简单的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动画这样的:

example

[EDIT1]它看起来像你的GFX对象使用transponed矩阵

这意味着变换的顺序颠倒,等式改变了一点...这里你的案例在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; 
} 
//--------------------------------------------------------------------------- 
+0

当我使用你的代码时,它做同样的事情。你测试过了吗?如果是这样,你能提供整个班级的代码吗? –

+0

你在#2下的等式似乎和我的等式一样。 _scale最终被取消,最终增加1.25。难道图形坐标与鼠标坐标不一样吗? –

+0

@NathanBierema是的,我在写作时犯了一个错误......(我之前做过很多次)早上很匆忙。请参阅已经添加的功能源代码(来自VCL,但您可以简单地将它移植到您的代码中)。如果即使这不起作用,你的鼠标坐标也不正确(不是相对于你的应用程序,而是相对于桌面) – Spektre

相关问题