Автоматическое объединение смежных прямоугольников

Я делал в XNA шутер с видом сверху, который требует прямоугольного столкновения для карты.

Столкновения стен для карты хранятся в текстовом файле в формате: rect[0,0,1024,8]

Значения соответствуют определению прямоугольника (x, y, ширина, высота).

Я думал, что могу написать отдельное приложение, которое может неграмотно просматривать данные изображения карты, определять черные пиксели (или любой цвет стены) и создавать там прямоугольники. По сути, эта программа будет генерировать прямоугольники, необходимые для столкновения. В идеале это было бы идеально по пикселям, для чего потребовалось бы что-то вроде тысячи прямоугольников шириной в 1 пиксель, покрывающих все стены.

Есть ли способ определить, какие из этих прямоугольников (или квадратов, я бы сказал) смежны друг с другом, а затем соединить их в более крупный (но все еще покрывающий ту же площадь) прямоугольник?

НАПРИМЕР. Допустим, у меня есть стена размером 10 на 2. Программа создаст 20 различных прямоугольников, каждый высотой в 1 пиксель. Как я могу эффективно определить, что эти прямоугольники смежные, и автоматически создать прямоугольник 10 на 2, покрывающий всю стену, вместо того, чтобы иметь 20 разных маленьких прямоугольников пикселей?

РЕДАКТИРОВАТЬ: Я разработал решение, которое соответствует моим целям, мой код для дальнейшего использования приведен ниже:

//map is a bitmap, horizontalCollisions and collisions are List<Rectangle>s
for (int y = 0; y < map.Height; y++) //loop through pixels
        {
            for (int x = 0; x < map.Width; x++)
            {
                if (map.GetPixel(x, y).Name == "ff000000") //wall color
                {
                    int i = 1;
                    while (map.GetPixel(x + i, y).Name == "ff000000")
                    {
                        if (i != map.Width - x)
                        {
                            i++;
                        }
                        if (i == map.Width - x)
                        {
                            break;
                        }
                    }
                    Rectangle r = new Rectangle(x, y, i, 1);//create and add
                    x += i - 1;
                    horizontalCollisions.Add(r);
                }
            }
        }
        for (int j = 0; j < horizontalCollisions.Count; j++)
        {
            int i = 1;
            Rectangle current = horizontalCollisions[j];
            Rectangle r = new Rectangle(current.X, current.Y + 1, current.Width, 1);
            while(horizontalCollisions.Contains(r))
            {
                i++;
                horizontalCollisions.Remove(r);
                r = new Rectangle(current.X, current.Y + i, current.Width, 1);
            }
            Rectangle add = new Rectangle(current.X, current.Y, current.Width, i);
            collisions.Add(add);
        }

            //collisions now has all the rectangles

По сути, он будет перебирать пиксельные данные по горизонтали. Когда он встречает пиксель стены, он останавливает счетчик и (используя цикл while) перемещает счетчик вправо, один за другим, пока он не достигнет пикселя, не являющегося стеной. Затем он создаст прямоугольник этой ширины и продолжит работу. После этого процесса появится большой список прямоугольников, каждый высотой 1 пиксель. В основном пучок горизонтальных линий. Следующий цикл будет проходить по горизонтальным линиям и, используя тот же процесс, что и выше, он обнаружит, что есть какие-либо прямоугольники с тем же значением X и тем же значением ширины под ним (y + 1). Он будет увеличиваться до тех пор, пока не останется ни одного, в котором будет создан один большой прямоугольник, а используемые прямоугольники будут удалены из списка. Окончательный результирующий список содержит все прямоугольники, из которых состоят все черные пиксели изображения (я думаю, довольно эффективно).


person Felix Guo    schedule 09.12.2012    source источник


Ответы (1)


Этикет может предложить мне прокомментировать это, а не добавить в качестве ответа, но у меня еще нет такой возможности, так что терпите.

Боюсь, я не могу перевести это в код для вас, но я могу послать вас к некоторым академическим статьям, в которых обсуждаются алгоритмы, которые могут делать некоторые из вещей, о которых вы просите.

В другой раз возник этот вопрос:

Статьи, связанные с этими вопросами:

Надеюсь, эти вопросы и документы помогут вам найти ответ, который вы ищете, или, по крайней мере, отпугнут вас к поиску другого решения.

person Rob Ocel    schedule 09.12.2012
comment
Спасибо за вашу помощь, я бегло просмотрел части статей (и испугался), но я написал базовый общий код, который у меня работал. Мне не нужно, чтобы это было суперэффективно. Я отредактировал свой исходный вопрос, добавив код и объяснение. Надеюсь, это поможет людям в будущем. - person Felix Guo; 09.12.2012