根据当前鼠标位置缩放图形 [英] Zooming graphics based on current mouse position

查看:35
本文介绍了根据当前鼠标位置缩放图形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据鼠标的当前位置缩放绘图.现在我的 onMouseWheel 方法看起来像这样(基于

[edit1] 看起来您的 gfx 对象使用转发矩阵

这意味着转换的顺序颠倒了,所以方程会发生一些变化......这是您在 C++ 中的案例示例:

void scr2obj(double &ox,double &oy,double sx,double sy){//ox=(sx-x0)/缩放;//oy=(sy-y0)/缩放;ox=(sx/缩放)-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)*缩放;sy=(y0+oy)*缩放;}//---------------------------------------------------------------------------void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled){双 mx0,my0;scr2obj(mx0,my0,mx,my);缩放/=1.25;//缩小obj2scr(mx0,my0,mx0,my0);//x0+=mx-mx0;//y0+=my-my0;x0+=(mx-mx0)/缩放;y0+=(my-my0)/缩放;_重绘=真;}//---------------------------------------------------------------------------void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled){双 mx0,my0;scr2obj(mx0,my0,mx,my);缩放*=1.25;//放大obj2scr(mx0,my0,mx0,my0);//x0+=mx-mx0;//y0+=my-my0;x0+=(mx-mx0)/缩放;y0+=(my-my0)/缩放;_重绘=真;}//---------------------------------------------------------------------------

I'm trying to zoom a drawing based on the current position of the mouse. Right now my onMouseWheel method looks like this (based on 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, and _translateY are member variables.

I'm scaling the graphics, translating it, and then drawing the lines like this:

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

This video shows what happens when I try to zoom in and the zoom out on a certain point. What am I doing wrong?

This is what the code looks like in a sample panel class for testing purposes:

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);
    }
}

解决方案

Too lazy to make the equations right (and most likely would made similar mistake as you... I do not know if it is just me but exactly this easy stuff I cant handle and drives me mad). Instead I am dealing with this kind of tasks as follows (it is much safer from mistakes):

  1. create transform functions between screen and world coordinates

    So your mouse position is in screen coordinates and rendered stuff is in world coordinates. As this is only 2D then it is easy. make function that converts between these two. Your world to screen transform (if I am not overlooking something) is this:

    g.ScaleTransform(_scale, _scale);
    g.TranslateTransform(_translateX, _translateY);
    

    so:

    screen_x=(world_x*_scale)+_translateX;
    screen_y=(world_y*_scale)+_translateY;
    

    So the reverse:

    world_x=(screen_x-_translateX)/_scale;
    world_y=(screen_y-_translateY)/_scale;
    

  2. change of zoom/scale

    The idea is that after zoom/scale change the mouse position should stay the same in world coordinates as before. so remember world coordinates of mouse before change. Then compute from it the screen position after change and the difference put into translation.

Here simple C++ example:

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;
    }
//---------------------------------------------------------------------------

the mx,my is actual mouse position in screen coordinates, the x0,y0 is the translation and zoom is the scale.

And here captured GIF animation of this:

[edit1] It looks like your gfx objects use transponed matrices

That means the order of transformations is reversed so the equations change a bit... Here your case example in 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; 
 } 
//---------------------------------------------------------------------------

这篇关于根据当前鼠标位置缩放图形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆