Let the user draw polygons in C#

draw polygons

This example shows how you can let the user draw polygons with the mouse. It represents each polygon as a list of points. It stores all of the finished polygons in a list of lists of points named Polygons, which is declared by the following code.

// Each polygon is represented by a List.
private List<List<Point>> Polygons = new List<List<Point>>();

When the user is drawing a new polygon, the program stores its points in a list of points named NewPolygon. The current mouse position, which is where the next point will be if the user clicks the mouse, is stored in variable NewPoint.

// Points for the new polygon.
private List<Point> NewPolygon = null;

// The current mouse position while drawing a new polygon.
private Point NewPoint;

The PictureBox‘s MouseDown event handler starts drawing a new polygon or adds a point to the current one.

// Start or continue drawing a new polygon.
private void picCanvas_MouseDown(object sender, MouseEventArgs e)
{
    // See if we are already drawing a polygon.
    if (NewPolygon != null)
    {
        // We are already drawing a polygon.
        // If it's the right mouse button, finish this polygon.
        if (e.Button == MouseButtons.Right)
        {
            // Finish this polygon.
            if (NewPolygon.Count > 2) Polygons.Add(NewPolygon);
            NewPolygon = null;
        }
        else
        {
            // Add a point to this polygon.
            if (NewPolygon[NewPolygon.Count - 1] != e.Location)
            {
                NewPolygon.Add(e.Location);
            }
        }
    }
    else
    {
        // Start a new polygon.
        NewPolygon = new List<Point>();
        NewPoint = e.Location;
        NewPolygon.Add(e.Location);
    }

    // Redraw.
    picCanvas.Invalidate();
}

The event handler does one of three things:

  • If you are currently drawing a polygon and you pressed the right mouse button, the code finishes the new polygon. If the polygon has more than 2 points, it adds it to the Polygons list.
  • If you are currently drawing a polygon and you pressed the left mouse button, the program adds a new point to the new polygon.
  • If you are not currently drawing a polygon, the code starts a new polygon.

The event handler finishes by invalidating the PictureBox so it redraws.

When you move the mouse, the PictureBox‘s MouseMove event handler updates the NewPoint position and invalidates the PictureBox to make it redraw.

// Move the next point in the new polygon.
private void picCanvas_MouseMove(object sender, MouseEventArgs e)
{
    if (NewPolygon == null) return;
    NewPoint = e.Location;
    picCanvas.Invalidate();
}

The PictureBox‘s Paint event handler draws the old polygons in blue and the new one in green.

// Redraw old polygons in blue. Draw the new polygon in green.
// Draw the final segment dashed.
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.Clear(picCanvas.BackColor);

    // Draw the old polygons.
    foreach (List<Point> polygon in Polygons)
    {
        e.Graphics.FillPolygon(Brushes.White, polygon.ToArray());
        e.Graphics.DrawPolygon(Pens.Blue, polygon.ToArray());
    }

    // Draw the new polygon.
    if (NewPolygon != null)
    {
        // Draw the new polygon.
        if (NewPolygon.Count > 1)
        {
            e.Graphics.DrawLines(Pens.Green, NewPolygon.ToArray());
        }

        // Draw the newest edge.
        if (NewPolygon.Count > 0)
        {
            using (Pen dashed_pen = new Pen(Color.Green))
            {
                dashed_pen.DashPattern = new float[] { 3, 3 };
                e.Graphics.DrawLine(dashed_pen, 
                    NewPolygon[NewPolygon.Count - 1],
                    NewPoint);
            }
        }
    }
}

First the event handler loops through the Polygons list to fill and draw each of the old polygons. Then, if the program is currently drawing a new polygon, the code uses the Graphics object’s DrawLines method to draw the new polygon so far. Finally the code draws a line between the new polygon’s last point and the current mouse position to show where the next point would be if you clicked the mouse there.


Download Example   Follow me on Twitter   RSS feed   Donate




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

23 Responses to Let the user draw polygons in C#

  1. Maceraperest says:

    how to make picturebox polygons clone & crope.I would be glad if you can help.

  2. Pingback: Let the user draw and move polygons in C# -

  3. Noman says:

    I want to make an open polygon that which not connects with first point

    • RodStephens says:

      Simply change the program’s call to DrawPolygon with a call to DrawLines.

      • Noman says:

        Thanks, If you make above file to do draw lines instead of Polygon and upload it, I will be very thankful to you.
        Your response will be appreciated.
        That above file should not connect the first point with the last point on right click so that open polygon can form.

  4. Noman says:

    Thanks alot Sir I have done with it. Thanks

  5. Noman says:

    In this Example, Why the next polygon is not starting from the previous polygon’s node. How I make it to do that ?

    • RodStephens says:

      I’m not sure what you want. You want the first corner of the next polygon to be the same as the last corner of the previous one?

      • Noman says:

        Yes like that, for example; I want to draw the 2D Frame of two stories and one bay as shown below. I want to draw first story first with 3 members then after this second story with 3 members with connected nodes. In this example there should be the 6 nodes when drawn.

                   _________
                   |       |
                   |_______|
                   |       |
                   |_______|
        • Noman says:

          Search for 2D concrete frame, I want to draw this.

          • RodStephens says:

            This is a very specialized application so I would be tempted to make a very specialized program for it. For example, if I understand what you want, the user could enter the number of floors on each level. Or perhaps use X and to indicate where frames should be. For example, this:

            X
            XX  X
            XXX X
            XXXXX

            Might mean this:

            +--+
            |  |
            +--+--+     +--+
            |  |  |     |  |
            +--+--+--+  +--+
            |  |  |  |  |  |
            +--+--+--+--+--+
            |  |  |  |  |  |
            +--+--+--+--+--+

            Another possibility would be to display a grid and let the user click squares to toggle whether or not they are part of the solution.

  6. Noman says:

    After disabled the moving node module.

  7. Robert says:

    Thanks for this great Post. I have a question:

    After creating the Polygons, i would like to order them on a new List<List> by the Polygon Position X and Y.
    This order them based on the First Point:
    PolygonsOrdered = Polygons.ToArray().OrderBy(points => points.ToArray()[0].X).ThenBy(points => points.ToArray()[0].X).ToList();

    i would like to check for the Min and/or Max Point on my Polygon and order the Polygons based on that.

    any Help will be appreciated

    • RodStephens says:

      This example isn’t really set up to let you manipulate the polygons much. It’s not trivial to rearrange a List<List<Point>>.

      One approach would be to convert the outer list into an array of lists of points. Then you could use Array.Sort to sort that array, using a comparer to compare two List<Points> to see which should come first in the array.

      However, if you want to perform these kinds of operations, then you’re probably better off building a Polygon class that holds the points that define a shape. Then you can store them in a list or array.

      You can also give the class a other useful features such as a Bounds property (which returns the minimum and maximum X and Y coordinates for a polygon), a Draw method, color properties, etc.

      Now you can use Array.Sort to sort the array of Polygon objects and the comparer can use their bounds to sort them.

  8. Javier says:

    For some reason I cannot migrate your files to Visual Studio 2013. It says that the files are read only. I checked the properties and they are not read only.
    Could you please update your files a newer version of Visual Studio? Thank you.

    • RodStephens says:

      I keep them in an older version because you can move forward but not backward. You can open the project with Visual Studio 2013, but if I moved them up to Visual Studio 2017, then you couldn’t.

      Usually the problem you’re seeing is caused by trying to open the project while it is still in the zip file. Visual Studio thinks it can open the project, but it really cannot and then the error message it gives isn’t helpful.

      Be sure to unzip the project that you download before you try to open it. In your case, it should ask if you want to convert the files to Visual Studio 2013.

  9. Aristide Vanwanzeele says:

    This is an extremely interesting subject and very well explained! Thanks very much for that.

    However, this example is based on Forms and I would like to apply this to C# WPF. As far as I know, I can’t – for instance – rely on the Invalidate() method to get a Paint() callbacks in WPF because that’s simply not available.

    What would be needed to convert this example to a WPF-based application?

    Best,
    –Aristide

    • RodStephens says:

      You’re correct that WPF does not use Paint events. You simply create a graphical object in WPF and it redraws itself automatically as needed.

      I don’t think I have a WPf example that lets the user draw polygons, but this example should help.

      I’ll see if I can make one that draws polygons at some point.

      • Geert Vancompernolle says:

        Hi Rod,

        I too was interested in such example. Thanks for pointing to an example. It has put me on the (hopefully) correct path to do what I wanted to do: “simulate” the Polygon form example in WPF.

        To give something back to your C# website with extremely useful tips and tricks about the graphics in C#, I’ve sent you an e-mail with the WPF version of the Polygons form example.

        If you want, you can use it as a starting point for your article. See it as my contribution to you/your website.

        However, since those are my first days in the graphical world of WPF in C#, I would appreciate if you could comment on things I’ve possibly done wrong.

        Best rgds,
        –Geert

      • JS-161B says:

        Hi Rod,

        Can you make the c# curve behave like this polygon sample?

        • RodStephens says:

          If you mean that you want to allow the user to draw a smooth curve, go the the index page and search for “smooth curve.” You’ll find a few examples in Windows Forms and WPF.

          If you want a closed curve in Windows Forms, use the example that draws a smooth curve but use the DrawClosedCurve method instead of the DrawCurve method.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.