2016-05-16 5 views
3

Ich versuche, eine Zeichnung basierend auf der aktuellen Position der Maus zu vergrößern. Gerade jetzt meine onMouseWheel Methode sieht wie folgt aus (basierend auf this StackOverflow answer):Zoomen von Grafiken basierend auf der aktuellen Mausposition

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 und _translateY sind Membervariablen.

ich die Grafiken Skalierung, Übersetzung, und dann die Zeilen wie diese Zeichnung:

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

This video zeigt, was passiert, wenn ich versuche, es zu vergrößern und der Zoom auf einem bestimmten Punkt aus. Was mache ich falsch?

Dies ist, was der Code wie in einer Probe Panel-Klasse für Testzwecke aussieht:

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

Können Sie den Code Ihrer Beispielanwendung hochladen? Ich denke, es hat etwas mit deiner Tonleiter zu tun, funktioniert es, wenn du anstelle der Multiplikation '_scale + = 0.25f' verwendest. Obwohl es nur eine Vermutung ist, weil ich gerade kein funktionierendes Beispiel habe. – dwonisch

+0

Ich habe eine Beispiel-Panel-Klasse hinzugefügt, die Sie einfach zu einem Formular hinzufügen können. Die Addition funktioniert nicht. Das würde den Zoom negativ werden lassen, wenn ich zu viel verkleinern würde. Es hat mit der Übersetzung zu tun. Die Skalierung funktioniert gut. –

Antwort

0

zu faul, um die Gleichungen richtig zu machen (und höchstwahrscheinlich würde aus ähnlichen Fehler, wie Sie ... Ich weiß nicht weiß, ob es nur ich ist, aber genau diese einfachen Sachen, die ich nicht verkrafte und mich verrückt macht). Stattdessen ich mit dieser Art von Aufgaben zu tun habe wie folgt (es ist viel sicherer, aus Fehlern):

  1. Transformation erstellen Funktionen zwischen Bildschirm und Weltkoordinaten

    So Position des Mauszeigers in Bildschirmkoordinaten und gerenderter Stoff ist in Weltkoordinaten. Da dies nur 2D ist, dann ist es einfach. make function, die zwischen diesen beiden konvertiert. Ihre Welt verändern zu screenen (wenn ich nicht etwas mit Blick auf), ist dies:

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

    so:

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

    So das Gegenteil:

    world_x=(screen_x-_translateX)/_scale; 
    world_y=(screen_y-_translateY)/_scale; 
    
  2. Änderung des Zoom/Skalierung

    Die Idee ist, dass nach Zoom/s cale Änderung der Mausposition sollte in Weltkoordinaten wie vorher gleich bleiben. Erinnere dich also an die Weltkoordinaten der Maus vor dem Wechsel. Dann berechne daraus die Bildschirmposition nach dem Wechsel und die Differenz in die Übersetzung.

Hier einfaches C++ Beispiel:

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

die mx,my wird tatsächliche Mausposition in Bildschirmkoordinaten, ist die x0,y0 die Übersetzung und zoom ist die Skala.

Und hier gefangen GIF Animation dieses:

example

[edit1] Es sieht aus wie verwenden Ihre gfx Objekte transponierte Matrizen

Das bedeutet, die Reihenfolge der Transformationen so umkehrt Die Gleichungen ändern sich ein bisschen ... Hier Ihr Fallbeispiel 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; 
} 
//--------------------------------------------------------------------------- 
+0

Es macht das gleiche, wenn ich Ihren Code verwende. Hast du das getestet? Wenn ja, können Sie den Code aus der gesamten Klasse bereitstellen? –

+0

Ihre Gleichung unter # 2 scheint das Gleiche zu tun wie meine Gleichung. Die _scale wird abgebrochen und du multiplizierst mit 1,25. Könnte es sein, dass die Grafikkoordinaten nicht den gleichen Ursprung haben wie die Mauskoordinaten? –

+0

@NathanBierema Ja, ich habe einen Fehler gemacht, während ich es geschrieben habe ... (das gleiche, was ich schon oft gemacht habe ..) war in Eile am Morgen. Siehe dazu den funktionalen Quellcode (aus VCL, aber Sie können ihn einfach in Ihren Code portieren) mit dem, was ich mir vorstelle. Wenn das auch nicht funktioniert, hast du falsche Mauskoordinaten (nicht relativ zu deiner App, sondern zum Desktop) – Spektre