Draw and move polygons snapping them to a grid in C#

example

This example lets the user draw and move polygons snapping them to a grid. See the example Let the user draw polygons, move them, and add points to them in C# for information on how the program lets the user draw, move, and add new points to polygons. See the example Draw and move line segments snapping to a grid in C# for information about snapping points to a grid.

The program uses the following SnapToGrid method to snap a point to the nearest grid location.

// The grid spacing.
private const int GridGap = 8;

// Snap to the nearest grid point.
private Point SnapToGrid(Point point)
{
    int x = GridGap * (int)Math.Round((float)point.X / GridGap);
    int y = GridGap * (int)Math.Round((float)point.Y / GridGap);
    return new Point(x, y);
}

This method takes a Point‘s X and Y coordinates, rounds them to the nearest multiple of GridGap, and returns a new Point with the rounded coordinates.

The program calls the SnapToGrid method whenever it deals with a point. For example, the following code shows the MouseDown event handler that executes when the mouse moves and no drawing or moving operation is in progress.

// See if we're over a polygon or corner point.
private void picCanvas_MouseMove_NotDrawing(
    object sender, MouseEventArgs e)
{
    Cursor new_cursor = Cursors.Cross;

    // See what we're over.
    Point mouse_pt = SnapToGrid(e.Location);
    List<Point> hit_polygon;
    int hit_point, hit_point2;
    Point closest_point;

    if (MouseIsOverCornerPoint(mouse_pt,
        out hit_polygon, out hit_point))
    {
        new_cursor = Cursors.Arrow;
    }
    else if (MouseIsOverEdge(mouse_pt, out hit_polygon,
        out hit_point, out hit_point2, out closest_point))
    {
        new_cursor = AddPointCursor;
    }
    else if (MouseIsOverPolygon(mouse_pt, out hit_polygon))
    {
        new_cursor = Cursors.Hand;
    }

    // Set the new cursor.
    if (picCanvas.Cursor != new_cursor)
    {
        picCanvas.Cursor = new_cursor;
    }
}

First this code passes the mouse’s current location to the SnapToGrid method. It then uses the MouseIdOverCornerPoint, MouseIsOverEdge, and MouseIsOverPolygon methods to see if the mouse is over part of a polygon. It then displays the appropriate cursor: Arrow if the mouse is over a polygon’s corner, the “add point” cursor if the mouse is over an edge, and Hand if the mouse is over the body of a polygon.

The example’s other methods similarly snap mouse locations to grid locations. For example, when you press the mouse down over a polygon, the program stores the offset from the mouse’s position (not snapped to the grid) and the polygon’s origin. Then the following code executes when you move the mouse to drag the polygon.

// Move the selected polygon.
private void picCanvas_MouseMove_MovingPolygon(
    object sender, MouseEventArgs e)
{
    // See how far the first point will move.
    int new_x1 = e.X + OffsetX;
    int new_y1 = e.Y + OffsetY;

    int dx = new_x1 - MovingPolygon[0].X;
    int dy = new_y1 - MovingPolygon[0].Y;

    // Snap the movement to a multiple of the grid distance.
    dx = GridGap * (int)(Math.Round((float)dx / GridGap));
    dy = GridGap * (int)(Math.Round((float)dy / GridGap));

    if (dx == 0 && dy == 0) return;

    // Move the polygon.
    for (int i = 0; i < MovingPolygon.Count; i++)
    {
        MovingPolygon[i] = new Point(
            MovingPolygon[i].X + dx,
            MovingPolygon[i].Y + dy);
    }

    // Redraw.
    picCanvas.Invalidate();
}

This code calculates the distances dx and dy that the polygon should be moved. It then rounds those values to the nearest multiple of GridGap, and moves the polygon’s points by the rounded distances. It finishes by invalidating the PictureBox to redraw the polygon in its new position.

Download the example to see the rest of the code.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in algorithms, drawing, geometry, graphics, mathematics and tagged , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *