Создание многоугольника из массива 2D плиток - PullRequest
1 голос
/ 05 октября 2009

У меня есть двумерный массив, который просто содержит логические значения, показывающие, есть ли плитка в этой точке в массиве или нет. Это работает следующим образом, скажем, если массив [5,6] имеет значение true, тогда в координате (5,6) есть плитка. Форма, описанная массивом, представляет собой связанный многоугольник, возможно, с отверстиями внутри него.

По сути, все, что мне нужно, это список вершин и граней, которые описывают форму в массиве.

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

Редактировать: Это все сделано, чтобы я мог взять фигуры и столкнуть их вместе.

Этот проект - всего лишь то, что я делаю, чтобы улучшить свои навыки программирования / физику и т. Д.

Edit2: Спасибо за помощь. В основном моя проблема была очень похожа на преобразование растрового изображения в векторное изображение. http://cardhouse.com/computer/vector.htm полезно, если кто-то еще в будущем столкнется с теми же проблемами, что и я.

Ответы [ 2 ]

1 голос
/ 06 октября 2009

Не зацикливайтесь на отдельных пикселях. Сфокусируйтесь на углах пикселей - точках, где встречаются четыре пикселя. Координаты этих углов будут работать как полуоткрытые координаты пикселей. Полуоткрытые границы включаются на нижней границе, но исключают на верхней границе, поэтому полуоткрытый диапазон от одного до трех равен {1, 2}.

Определение набора ребер - однопиксельных длинных линий (вертикальных или горизонтальных) между двумя пикселями. Затем сформируйте граф смежности - два ребра смежны, если они разделяют точку.

Затем определите связанные наборы ребер - подграфы, где каждая точка связана, прямо или косвенно, с любой другой. Логически, большинство связанных подграфов должны образовывать замкнутые циклы, и вы должны убедиться, что ВСЕ циклы считаются простыми замкнутыми циклами.

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

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

  1 0        0 1
  0 1        1 0

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

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

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

Чтобы проверить, является ли конкретный цикл дырой или нет, выберите (например) крайний левый вертикальный край пикселя (в цикле). Если пиксель справа заполнен, петля является границей многоугольника. Если пиксель слева заполнен, петля является дырой. Примечание. Хороший тестовый пиксель - это, вероятно, тот, который вы нашли, когда нашли первый край пикселя, перед тем как обвести контур. Это может быть не самый левый такой край, но он будет самым левым / самым верхним в этой строке сканирования.

Последняя проблема упрощается - определение, где края пикселей сходятся в прямые линии. Это, вероятно, может быть встроено в сканирование, которое в первую очередь идентифицирует цикл, но, вероятно, лучше всего найти угол перед началом сканирования. После этого каждая строка идентифицируется с помощью цикла «пока я могу продолжить трассировку в одном направлении», но следите за проблемами, касающимися двух полигонов, соприкасающихся в углу.

Попытка объединить все это может звучать как сложный беспорядок, но хитрость заключается в том, чтобы разделить проблемы на разные классы / функции, например, используя классы, которые предоставляют абстрактные представления нижележащих слоев, таких как ваше растровое изображение. Не беспокойтесь слишком сильно о накладных расходах на вызовы или оптимизации - встроенная и другая оптимизация компилятора должна справиться с этим.

Что было бы действительно интересно, так это более интеллектуальная трассировка, которую некоторые программы векторной графики делали уже некоторое время, где можно получить диагонали, кривые и т. Д.

1 голос
/ 05 октября 2009

Вам нужно будет уточнить желаемый результат. Что-то вроде следующего

██  ██
  ██
██  ██

данный

1 0 1
0 1 0
1 0 1

как вход? Если да, это кажется довольно тривиальным - почему бы вам просто не сгенерировать один четырехугольник на элемент массива, если он есть, иначе ничего?

Вы можете решить эту проблему, используя простой конечный автомат. Текущее состояние состоит из текущей позиции (x, y) и текущего направления - влево (L), вправо (R), вверх (U) или вниз (D). «X» - это текущая позиция, и есть восемь соседей, которые могут контролировать изменение состояния.

0 1 2
7 X 3
6 5 4

Тогда просто следуйте следующим правилам - в состоянии X, Y, D проверьте два заданных поля и измените состояние соответствующим образом.

X,Y,R,23=00 => X+1,Y,D
X,Y,R,23=01 => X+1,Y,R
X,Y,R,23=10 => X+1,Y,U
X,Y,R,23=11 => X+1,Y,U

X,Y,D,56=00 => X,Y+1,L
X,Y,D,56=01 => X,Y+1,D
X,Y,D,56=10 => X,Y+1,R
X,Y,D,56=11 => X,Y+1,R

...
...