0

(New to this and playing around with a basic paint application) Ive found detailed instructions to code a flood-fill but as i am new it is very hard to understand every bits of it, and instead of copying, i would like to try to make my own simple(small scale) flood-fill.

Would it be possible to use fillpath as a flood-fill? i would draw paths and use my mouse to determine my x,y, on screen and have the graphicspath find out if it has borders(points from the drawn paths) and if so, fill these paths with a color?

this is what ive come up with but obviously it doesnt work, so how would i go about to make this working?

namespace WindowsFormsApplication3
{
 public partial class Form1 : Form
 {
    Graphics g;
    readonly Pen pen = new Pen(Color.Navy, 2);
    Point oldCoords;
    GraphicsPath graphicsPaths = new GraphicsPath();
    bool spaceFound = false;


    public Form1()
    {
        InitializeComponent();
        g = panel1.CreateGraphics();
    }

    private void panel1_MouseDown(object sender, MouseEventArgs e)
    {
        Point mousePt = new Point(e.X, e.Y);

        if (e.Button == MouseButtons.Right &&             
               graphicsPaths.IsVisible(mousePt))
        {
            spaceFound = true;
        }
    }

    private void panel1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            if (oldCoords.IsEmpty)
                graphicsPaths.StartFigure();
            else
            {
                graphicsPaths.AddLine(oldCoords, new Point(e.X, e.Y));
                g.DrawPath(pen, graphicsPaths);
            }
            oldCoords = new Point(e.X, e.Y);
        }
        else
            oldCoords = Point.Empty;
    }

    private void panel1_MouseUp(object sender, MouseEventArgs e)
    {

    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        g.DrawPath(pen, graphicsPaths);

        if(spaceFound == true)
        {
            g.FillPath(Brushes.AliceBlue, graphicsPaths);
        }
    }
  }

}

1 Answers1

1

Yes, this is quite possible; of course you would want to store the path in a List<GraphicsPath> in the MouseUp event to allow for more filled shapes..

You need to correct a few issues in your code:

  • Set the path.FillMode to Winding
  • Never cache a Graphics object
  • Never use control.CreateGraphics()
  • Don't cache Pens or Brushes
  • Only draw in the Paint event, unless you do not want the drawing to persist

The last point might actually apply here: Maybe you don't want the currently drawing outline to stay visible? In that, and only that case you can stick with drawing it in the MouseMove with a Graphics object created there on the fly.

enter image description here

Here is a corrected version:

Point oldCoords;
GraphicsPath graphicsPaths = new GraphicsPath() { FillMode = FillMode.Winding };
bool spaceFound = false;

private void drawPanel1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right && graphicsPaths.IsVisible(e.Location))
    {
        spaceFound = true;
        drawPanel1.Invalidate(); 
    }
}

private void drawPanel1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        if (oldCoords.IsEmpty)  graphicsPaths.StartFigure();
        else
        {
            graphicsPaths.AddLine(oldCoords, new Point(e.X, e.Y));
            drawPanel1.Invalidate(); 
        }
        oldCoords = new Point(e.X, e.Y);
    }
    else oldCoords = Point.Empty;
}

private void drawPanel1_Paint(object sender, PaintEventArgs e)
{
    using (Pen pen = new Pen(Color.Black, 2f))
        e.Graphics.DrawPath(pen, graphicsPaths);

    if (spaceFound == true)
    {
        e.Graphics.FillPath(Brushes.AliceBlue, graphicsPaths);
    }
}

Note that it will fill your path but not in the way of a true floodfill, i.e. it will always fill the whole path, not just the innermost segment you have clicked in. For a true floodfill much more involved code is needed that actually goes over all neighbouring pixels starting at the click location..

Examples of a true floodfill are here and here

Community
  • 1
  • 1
TaW
  • 53,122
  • 8
  • 69
  • 111
  • wow this is cool, you seem to know a lot, thank you. Im gonna try and figue out storing the paths in a list so i can have multiple shapes with different coloured fills in it. You showed my a great example yesterday, see if i combine that in here. – Alex Turner Aug 16 '16 at 08:43
  • Note that it will fill your path but not in the way of a true floodfill, i.e. it will always fill the whole path, not just the innermost segment you have clicked in. For a true floodfill much more involved code is needed that actually goes over all neighbouring pixels starting at the click location.. – TaW Aug 16 '16 at 08:51
  • so i would not be able to store a fill in a list and store the list in a new list and clear the first list and so on? to be able to fill new shapes? – Alex Turner Aug 16 '16 at 09:16
  • Sure you can store the paths; what I meant is: They are paths with fills, not real flood fills. A real floodfill will only fill one (inner) segement but a filled path with several crossing lines will have either several filled segments (FillMode=Alternate) or will fill the outer border (FillMode=Winding... – TaW Aug 16 '16 at 09:21