2009-12-12 6 views
13

Ich versuche, Snap-to-Grid-Funktionalität zu erstellen, um zur Laufzeit verwendet werden, aber ich habe Probleme mit dem Fangen Teil. Ich habe erfolgreich ein gepunktetes Gitter auf einem Panel gezeichnet, aber wenn ich dem Panel ein Label-Steuerelement hinzufüge, wie schnappe ich die obere, linke Ecke des Labels an den nächsten Punkt?C# Erstellen Snap-To-Grid-Funktionalität

Dank

Antwort

17

pos.x - pos.x% gridwidth sollte es für Sie tun

+1

Vielen Dank! – Nathan

+1

Denken Sie daran, dass der obige Code an der Gitternetzlinie zwar näher an Null liegt. Um nach links oder rechts zu springen, könnte man z. B. testen, ob pos.x% gridWidth mehr oder weniger als gridWidth/2 ist. Denken Sie daran, dass Sie für Koordinaten unter Null einen anderen Fall erhalten. Das sollte Ihnen alle Werkzeuge geben, die Sie brauchen. – Pedery

+1

Wenn Sie gridWidth = 3. für einen PunktX = 5 haben, wird er auf 3 abgebildet, wenn er auf 6 abgebildet werden sollte. Siehe meine Antwort für eine ausführlichere Antwort. –

0

Nur ganze Zahlen verwenden und die Teilung nur funktionieren: die Modulo-Lösung ist

int xSnap = (xMouse/gridWidth) * gridWidth; 
int ySnap = (yMouse/gridHeight) * gridHeight; 

Außer natürlich so viel eleganter.

+0

Sie multiplizieren und dividieren durch gridWidth. Dadurch werden sie gelöscht, wobei xMouse immer gleich bleibt. – Julian

+2

-1: wie @Julian sagte, zeigt elementare Mathematik, dass diese Antwort Unsinn ist – ssc

1
private enum SnapMode { Create, Move } 
private Size gridSizeModeCreate = new Size(30, 30); 
private Size gridSizeModeMove = new Size(15, 15); 

private Point SnapCalculate(Point p, Size s) 
{ 
    double snapX = p.X + ((Math.Round(p.X/s.Width) - p.X/s.Width) * s.Width); 
    double snapY = p.Y + ((Math.Round(p.Y/s.Height) - p.Y/s.Height) * s.Height); 
    return new Point(snapX, snapY); 
} 

private Point SnapToGrid(Point p, SnapMode mode) 
{ 
    if (mode == SnapMode.Create) 
     return SnapCalculate(p, gridSizeModeCreate); 
    else if (mode == SnapMode.Move) 
     return SnapCalculate(p, gridSizeModeMove); 
    else 
     return new Point(0, 0); 
} 
3

Hier ist eine Lösung, die Runden zum nächstgelegenen Rasterpunkt:

public static readonly Size Grid  = new Size(16, 16); 
    public static readonly Size HalfGrid = new Size(Grid.Width/2, Grid.Height/2); 

    // ~~~~ Round to nearest Grid point ~~~~ 
    public Point SnapCalculate(Point p) 
    { 
     int  snapX = ((p.X + HalfGrid.Width )/Grid.Width ) * Grid.Width; 
     int  snapY = ((p.Y + HalfGrid.Height)/Grid.Height) * Grid.Height; 

     return new Point(snapX, snapY); 
    } 
1

Dies ist für mich besser funktioniert, wie es den Punkt bewegt sich, je nachdem, wie nahe es zum nächsten oder vorherigen gird -Punkt:

  if (pt.X % gridWidth < gridWidth/2) 
       pt.X = pt.X - pt.X % gridWidth; 
      else 
       pt.X = pt.X + (gridWidth - pt.X % gridWidth); 

      if (pt.Y % gridHeight < gridHeight/2) 
       pt.Y = pt.Y - pt.Y % gridHeight; 
      else 
       pt.Y = pt.Y + (gridHeight - pt.Y % gridHeight); 
14

Ich glaube nicht, dass die angenommene Antwort korrekt ist. Hier ist der Grund:

wenn die gridwidth = 3, die einen Punkt auf x wie 4: 3 Karte sollte aber x = 5 sollte Karte bis 6. Pedery Antwort unter Verwendung werden sie beide Karte 3.

Für eine korrekte Ergebnis müssen Sie so abrunden (Sie können Float verwenden, wenn Punkte Brüche sind):

// Sagen wir.

int gridCubeWidth = 3; 
int gridCubeHeight = 3; 

int newX = Math.Round(oldX/gridCubeWidth) * gridCubeWidth; 
int newY = Math.Round(oldY/gridCubeHeight) * gridCubeHeight;