填充矩形
本文关键字:填充矩形 | 更新日期: 2023-09-27 17:52:47
我创建了一个winform程序,它使用一个Graphics对象和两个for循环来根据用户输入生成一个方形网格。
我还创建了一个方法,通过使用与网格相同的坐标,用随机颜色填充网格中的每个正方形。
现在我想用光标的位置,通过点击来独立绘制每个正方形。我该怎么做呢?
你为什么不直接跟踪网格线,这样就知道你在哪个方格内点击了?根据这些知识,你可以画一个属于自己的正方形
洪水填充是最简单的。与其他方法相比,它速度很慢,而且占用堆栈空间,但在使用时间不到15年的计算机上,这应该不是问题。
正如@Ron提到的,典型的递归填充很容易破坏堆栈。因此,我修改了代码以使用Stack<>
实例(我认为它是从堆中分配的)和所谓的"数据递归"。对于大的(2000x2000+像素)区域,它仍然很慢,但对于小的区域应该没问题。
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);
}
}
}
注意我甚至没有尝试编译这个
基本上:
- 点击:读取用户点击的颜色(背景色)。
- 递归开始:
- 读取用户点击的颜色(背景色)。
- 确保它与步骤1中的背景颜色相同。其他回报。
- 设置像素为填充颜色
- 对于周围的8个像素,递归到步骤3。当您读取的背景像素与初始读取的背景颜色不同时,递归停止。