唉,这是一个大学类型的问题,但是我一直在努力奋斗。
我需要生成非重叠的大型矩形测试集,然后可以用来测试找到它们之间的邻接关系的算法。测试集中可能需要超过10000到100000个矩形。我一直在网上搜索如何生成这样的测试集的例子,但没有提出任何建议。我知道我可以使用纯粹的暴力方法,并且每次生成随机矩形时,检查它是否与任何其他矩形重叠,但这似乎生成测试集将最终花费几天,如果不再!
任何人都知道如何去做,或者至少我应该开始寻找?
答案 0 :(得分:0)
我发现你的想法充满乐趣和挑剔,因此尝试使用矩阵解决方案。
基本上,这个想法是(当以像素说话时)创建一个与MaxWidthOfRectangle *(NumberOfRectangles)的平方根相同宽度和高度的布尔矩阵(只是为了简单起见,宽度和高度相同)。
接下来,对于矩阵中的每个条目,在最小和最大边界之间生成一个随机矩形。并在矩阵中为特定矩形设置所有bool。现在,当生成下一个矩形时,您可以简单地检查所需位置的“周围”,以确定您可以占用多少空间,而不必估计大小,并在相互冲突时与其他矩形进行比较。
我的代码:
class RectangleGenerator
{
readonly bool[,] _matrix;
readonly int _size;
readonly int _minimalBoxSize;
readonly int _maximumBoxSize;
readonly Random _random = new Random(1);
readonly List<Point> _offsets;
public bool[,] Matrix { get { return _matrix; } }
public RectangleGenerator(int size, int minimalBoxSize, int maximumBoxSize)
{
_matrix = new bool[size, size];
_size = size;
_minimalBoxSize = minimalBoxSize;
_maximumBoxSize = maximumBoxSize;
_offsets = new List<Point>(size * size);
Reset();
}
public IEnumerable<Rectangle> Calculate()
{
while (_offsets.Count > 0)
{
Point currentPoint = _offsets[_offsets.Count - 1];
_offsets.RemoveAt(_offsets.Count - 1);
if (!_matrix[currentPoint.X, currentPoint.Y])
{
Rectangle rectangle;
if (TryCreateNextRectangle(currentPoint.X, currentPoint.Y, out rectangle))
{
// fill the matrix with the rectangle + padding
int startFillX = Math.Max(0, rectangle.Left);
int startFillY = Math.Max(0, rectangle.Top);
int endFillX = Math.Min(_size, rectangle.Right);
int endFillY = Math.Min(_size, rectangle.Bottom);
for (int fillX = startFillX; fillX < endFillX; fillX++)
for (int fillY = startFillY; fillY < endFillY; fillY++)
{
_matrix[fillX, fillY] = true;
}
yield return rectangle;
}
}
}
}
private bool TryCreateNextRectangle(int x, int y, out Rectangle rectangle)
{
int maxWidth = DetermineMaxWidth(x, y, _minimalBoxSize);
int maxHeight = DetermineMaxHeight(y, x, maxWidth);
if (maxWidth < _minimalBoxSize || maxHeight < _minimalBoxSize)
{
rectangle = Rectangle.Empty;
return false;
}
int width = _random.Next(_minimalBoxSize, maxWidth);
int height = _random.Next(_minimalBoxSize, maxHeight);
rectangle = new Rectangle(x, y, width, height);
return true;
}
private int DetermineMaxWidth(int x, int y, int height)
{
int result = Math.Min(_maximumBoxSize, _size - x);
for (int offsetX = 0; offsetX < result; offsetX++)
for (int offsetY = 0; offsetY < height; offsetY++)
{
if (_matrix[x + offsetX, y + offsetY])
{
result = offsetX;
break;
}
}
return result;
}
private int DetermineMaxHeight(int y, int x, int width)
{
int result = Math.Min(_maximumBoxSize, _size - y);
for (int offsetY = 0; offsetY < result; offsetY++)
for (int offsetX = 0; offsetX < width; offsetX++ )
{
if (_matrix[x + offsetX, y + offsetY])
{
result = offsetY;
break;
}
}
return result;
}
public void Reset()
{
// append for padding:
for (int x = 0; x < _size; x++)
for (int y = 0; y < _size; y++)
{
_matrix[x, y] = false;
if (_size - x >= _minimalBoxSize && _size - y >= _minimalBoxSize)
{
_offsets.Add(new Point(x, y));
}
}
_offsets.Sort((x, y) => x == y ? 0 : _random.Next(-1, 1));
}
}