Alex Turner
Alex Turner

Reputation: 45

Use Fillpath with mouse input as flood fill between drawn paths?

(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);
        }
    }
  }

}

Upvotes: 0

Views: 187

Answers (1)

TaW
TaW

Reputation: 54433

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

Upvotes: 1

Related Questions