Reputation: 135
Ive created a winform-program that uses a Graphics object and 2 for-loops to generate a square grid, depending on user input.
I also created a method that fills each square in the grid with a random color by using the same coordinates as the grid.
Now I want to paint each square independently by clicking on it, using the cursor position. How should i do this?
Upvotes: 1
Views: 401
Reputation: 3636
Why don't you just keep track of the gridlines and thus know what square you clicked within? From this knowledge you could paint a square where one belongs.
Upvotes: 2
Reputation: 29061
A flood fill is easiest. It's slow compared to other methods and eats stack space, but it shouldn't be a problem on a computer that's less than 15 years old.
Update
As @Ron mentioned, a typical recursive floodfill blows the stack pretty easily. So, I modified the code to use a Stack<>
instance (which I believe is allocated from the heap) and so-called "data recursion". It's still pretty slow for large (2000x2000+ pixel) areas, but should be just fine for small ones.
bool[] canDraw;
/// <summary>
/// make sure that the given point is within our image boundaries.
/// BufferSize(Point) contains the dimensions of the image buffer.
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
bool InBounds(Point p)
{
return p.X >= 0 && p.X < BufferSize.X && p.Y >= 0 && p.Y < BufferSize.Y;
}
/// <summary>
/// make sure that we haven't already drawn this pixel and that it has
/// valid coordinates
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
bool CanDraw(Point p)
{
return InBounds(p) && canDraw[p.Y * BufferSize.X + p.X];
}
/// <summary>
/// Heap "stack" to track which pixels we need to visit
/// </summary>
Stack<Point> fillStack = new Stack<Point>();
/// <summary>
/// initialize recursion.
/// </summary>
/// <param name="startPosition"></param>
/// <param name="fillColor"></param>
void Fill(Point startPosition, Color fillColor)
{
canDraw = Enumerable.Repeat(true, BufferSize.X * BufferSize.Y).ToArray();
var backgroundColor = GetPixel(startPosition);
if (backgroundColor != fillColor)
{
fillStack.Push(startPosition);
RecurseFloodFill(fillColor, backgroundColor);
}
}
/// <summary>
/// data-recurse through the image.
/// </summary>
/// <param name="fillColor">Color we want to fill with</param>
/// <param name="backgroundColor">Initial background color to overwrite</param>
void RecurseFloodFill(Color fillColor, Color backgroundColor)
{
while (fillStack.Count > 0 && !IsExiting)
{
/*if (fillStack.Count != depth)
Debug.WriteLine("Depth: {0}", depth = fillStack.Count);
*/
var position = fillStack.Pop();
if(!CanDraw(position))
continue;
var color = GetPixel(position);
if (color != backgroundColor)
continue;
SetPixel(position, fillColor);
for(var i=position.X-1;i<=position.X+1;i++)
for (var j = position.Y - 1; j <= position.Y + 1; j++)
{
var p = new Point(i, j);
fillStack.Push(p);
}
}
}
Note that I haven't even tried to compile this.
Basically:
Upvotes: 1