Let the user draw polygons, move them, and add points to them in C#

draw polygons, move them, and add points to them

This example lets the user draw polygons, move them, and add points to them. It’s an extension of the example Let the user draw and move polygons in C#. See that example for a description of most of this program’s code.

The previous version lets you click to create polygons. It also lets you click and drag to move polygon vertices or the polygons themselves. This example adds the ability to add new points to a polygon. If you move the mouse over a polygon’s edge, the program changes its cursor to an “add point” cursor (a little box with a plus sign in it). If you click, the program adds a new point to the polygon at that position.

Adding new points requires three main changes: detecting when the mouse is over a polygon’s edge, displaying the “add point” cursor, and adding the new point.

At design time, I added a resource containing the “add point” cursor as a bitmapped image. When the program starts, it uses the following code to use that image to create the “add point” cursor.

// The add point cursor.
private Cursor AddPointCursor;

// Create the add point cursor.
private void Form1_Load(object sender, EventArgs e)
{
    AddPointCursor = new Cursor(
        Properties.Resources.add_point.GetHicon());
}

This code simply gets the “add point” image, uses its GetHicon method to get a handle to the image as an icon, and then passes the handle to the Cursor class’s constructor.

When the program is not drawing a new polygon, the PictureBox‘s MouseMove event handler uses a series of if-else statements to determine where the mouse is and what kind of cursor the program should display. The following code shows how it displays the “add point” cursor.

...
else if (MouseIsOverEdge(mouse_pt, out hit_polygon,
    out hit_point, out hit_point2, out closest_point))
{
    new_cursor = AddPointCursor;
}
...

If the MouseIsOverEdge method determines that the mouse’s position is over a polygon’s edge, this code displays the new cursor. The following code shows the MouseIsOverEdge method. (This is where things start to get interesting.)

// See if the mouse is over a polygon's edge.
private bool MouseIsOverEdge(Point mouse_pt,
    out List hit_polygon, out int hit_pt1,
    out int hit_pt2, out Point closest_point)
{
    // Examine each polygon.
    // Examine them in reverse order to check those on top first.
    for (int pgon = Polygons.Count - 1; pgon >= 0; pgon--)
    {
        List polygon = Polygons[pgon];

        // See if we're over one of the polygon's segments.
        for (int p1 = 0; p1 < polygon.Count; p1++)
        {
            // Get the index of the polygon's next point.
            int p2 = (p1 + 1) % polygon.Count;

            // See if we're over the segment between these points.
            PointF closest;
            if (FindDistanceToSegmentSquared(mouse_pt,
                polygon[p1], polygon[p2], out closest) <
                    over_dist_squared)
            {
                // We're over this segment.
                hit_polygon = polygon;
                hit_pt1 = p1;
                hit_pt2 = p2;
                closest_point = Point.Round(closest);
                return true;
            }
        }
    }

    hit_polygon = null;
    hit_pt1 = -1;
    hit_pt2 = -1;
    closest_point = new Point(0, 0);
    return false;
}

This method loops through the polygons. It loops through them in reverse order so they are considered from top to bottom. That way if the mouse is over multiple polygons’ edges, the program picks the polygon that is higher in the stacking order.

For each polygon, the program loops through the polygon’s points. For each point, it determines the index of the following point and calls the FindDistanceToSegmentSquared method to see if the mouse is within a given minimum distance of the segment between the two points. If it is, the MouseIsOverEdge method records the polygon and points and returns true.

If it finishes checking all of the polygons without finding an edge under the mouse, MouseIsOverEdge returns false.

See the example Find the shortest distance between a point and a line segment in C# to learn how the FindDistanceToSegmentSquared method works.

The last new part of the program is the code that creates the new point. When you click the mouse, the picCanvas_MouseDown event handler executes. If the program is drawing a new polygon, the code adds a new point to it. Otherwise the program uses the following code to determine whether it should add a new point to an existing polygon.

...
else if (MouseIsOverEdge(mouse_pt, out hit_polygon,
    out hit_point, out hit_point2, out closest_point))
{
    // Add a point.
    hit_polygon.Insert(hit_point + 1, closest_point);
}
...

If the MouseIsOverEdge method indicates that the mouse is over a polygon’s edge, the program inserts a new point in the polygon under the mouse. It adds the new point at the index 1 greater than the first point on the segment under the mouse. For example, suppose the mouse is above the segment connecting the points with indices 7 and 8. Then the program adds the new point at position 8 in the polygon’s list of points so it lies between the two existing points.

That’s all there is to the new “add point” feature. See the previous example for additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in algorithms, drawing, graphics, mathematics and tagged , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Let the user draw polygons, move them, and add points to them in C#

  1. Pingback: Draw and move polygons snapping them to a grid in C# -

  2. Pooja Shahane says:

    Thank you….it is very helpful….But I want to draw same polygon according to user’s input length of sides….means user should dynamically add length of sides in textboxes…accordingly polygon should add on picturebox…then user can move,resize and add points to it…

    • RodStephens says:

      I’m not sure what you mean. Do you mean the user enters points in a text box? You should be able to use the string class’s Split method to break the values into points and then use float.Parse to parse them.

Leave a Reply

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