生成非重叠矩形测试集

时间:2011-08-18 10:16:05

标签: testing

唉,这是一个大学类型的问题,但是我一直在努力奋斗。

我需要生成非重叠的大型矩形测试集,然后可以用来测试找到它们之间的邻接关系的算法。测试集中可能需要超过10000到100000个矩形。我一直在网上搜索如何生成这样的测试集的例子,但没有提出任何建议。我知道我可以使用纯粹的暴力方法,并且每次生成随机矩形时,检查它是否与任何其他矩形重叠,但这似乎生成测试集将最终花费几天,如果不再!

任何人都知道如何去做,或者至少我应该开始寻找?

1 个答案:

答案 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));
        }
    }