Вот способ сделать это без использования растеризации, то есть с использованием только чистых чисел.
Примечание : Это не O (n log n), больше похоже на O (n ^ 2). Это, однако, решение. Является ли это ответом, вероятно, нет, если O (n log n) является требованием.
- Создать список всех уникальных X-координат левого и правого краев (в одном списке)
- Когда вы строите этот список, для каждой координаты также связываете с ней список прямоугольников и указывает в этом списке, является ли X-координата, с которой связан список, левой или правой кромкой прямоугольника
- Сортировка списка координат по возрастанию слева направо
- Создать новый список прямоугольников, изначально пустой
- Пробежаться по списку координат и обработать для него связанный список прямоугольников
- Все прямоугольники в связанном списке, которые обозначены как имеющие координату в качестве левого края, должны быть добавлены в список, который вы создали в 4.
- Все прямоугольники с координатой в качестве правого края должны быть удалены.
- Порядок добавления и удаления должен выполняться в обратном порядке: сначала вы хотите удалить прямоугольники с правым краем, а затем вы добавили все прямоугольники с левым краем
- Теперь, прежде чем вы удалите прямоугольники из списка, который вы создали в 4, вы хотите обработать их. Вы обрабатываете их, рассматривая их как «под прямоугольники». Их «новая» координата левого края - это X-координата, которую вы обработали в предыдущей итерации цикла (в 5), а новый правый край - текущая X-координата, обрабатываемая
- Выходные данные алгоритма представляют собой набор пар координат (две X-координаты слева и справа), каждая пара имеет связанный список прямоугольников (вертикальная полоса)
Вывод должен быть таким:
- X = 1..2, Rects = A
- X = 2..3, Rects = A, B
- X = 3,4, Rects = A, B, C
- X = 4,5, Rects = A, C
- X = 5,6, Rects = C
Позвольте мне проиллюстрировать процесс до сих пор
+-------------------+
|A |
| +----------+-----+
| |C | |
| +-----+----+ | |
| |B | | | |
| | +----+-----+-----+
| | | |
+--+----------+-----+
| |
+----------+
^ ^ ^ ^ ^ ^
1 2 3 4 5 6 <-- X-coordinates
Связанные прямоугольники:
- слева: A, справа: (нет)
- слева: B, справа: (нет)
- слева: C, справа: (нет)
- слева: (нет), справа: B
- слева: (нет), справа: A
- слева: (нет), справа: C
Теперь вы создаете пустой список L=[]
и начинаете обработку координат и связанных прямоугольников:
Х = 1
Список пуст, ничего не обрабатывается
Нечего убирать
Добавить A: L = [A]
* * Х тысяча шестьдесят-восемь = 2
Список содержит прямоугольники, список процессов в виде прямоугольников, у которых левый край X = 1 и правый край X = 2 (две координаты, которые мы обработали до сих пор), и используют их исходные верхнюю и нижнюю координаты.
Нечего удалять.
Добавить B: L = [A, B]
* 1 072 * Х = 3
Список содержит прямоугольники, обрабатывает список (как A, так и B) одинаково, обрабатывает их как временно имеющие левую и правую координаты как X = 2 и X = 3, и используют их исходные верхнюю и нижнюю координаты.
Нечего убирать
Добавить C: L = [A, B, C]
* * Х тысяча семьдесят шесть = 4
Обработайте три прямоугольника так же, как и выше, временные координаты слева и справа равны X = 3 и X = 4
Удалить B: L = [A, C]
Нечего добавить
Х = 5 и Х = 6
Обработайте их точно так же.
Это означает, что у вас получатся «полосы» прямоугольников, вот так (я их немного раздвинул, чтобы проиллюстрировать, что это полосы, но они расположены непрерывно, как на исходной диаграмме) ):
+--+ +-----+ +----+ ------+
|A | | | | | | |
| | | | +----+ +-----+ +-----+
| | | | |C | | | | |
| | +-----| +----+ | | | |
| | |B | | | | | | |
| | | | +----+ +-----| +-----+
| | | | | | | |
+--+ +-----+ +----+ +-----+
| | | |
+-----+ +----+
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
1 2 2 3 3 4 4 5 5 6
Хорошо, теперь у вас есть выход, набор пар координат, каждая пара имеет связанный список прямоугольников.
Теперь мы делаем трюк. Мы обрабатываем вертикальную полосу точно таким же образом, только на этот раз мы используем координаты Y в качестве разделителей. Давайте обработать полосу между 3 и 4 выше. Помните, что у полосы есть левая и правая координаты 3 и 4.
Полоска выглядит так:
^ +----+ <-- 1
A | |
| ^ +----+ <-- 2
| C | |
| ^ | +----+ <-- 3
| B | | |
| | V +----+ <-- 4
| | | |
V | +----+ <-- 5
| | |
V +----+ <-- 6
Список координат с прямоугольниками:
- Top = A, Bottom = (нет)
- Top = C, Bottom = (нет)
- Верх = B, Низ = (нет)
- Верх = (нет), Низ = C
- Верх = (нет), Низ = A
- Верх = (нет), Низ = B
Новый пустой список L = []
Обработка координат:
y = 1
Ничего не обрабатывать (L = [])
Добавить A в список, L = [A]
Y = 2
Процесс A с временно имеющими верхнюю и нижнюю координаты Y = 1 и 2 (и помните, что он также имеет временные левую и правую координаты X = 3 и 4
Добавить C, L = [A, C]
y = 3
Процесс A и C, оба теперь имеют временные координаты (3, 2) - (4, 3)
Добавить B, L = [A, B, C]
Y = 4
Процессы A, B и C, все из которых имеют координаты (3, 3) - (4, 4)
Удалить C, L = [A, B]
Y = 5
Процессы A и B, координаты (3, 4) - (4, 5)
Удалить A, L = [B]
* * 1 134 Y = 6
Процесс B, координаты (3, 5) - (4, 6)
Конечный результат:
пар Y-координат с ассоциированными с ними прямоугольниками (которые также временно получили новые X-координаты):
- (3, 1) - (4, 2) - A
- (3, 2) - (4, 3) - А, С
- (3, 3) - (4, 4) - А, В, С
- (3, 4) - (4, 5) - А, В
- (3, 5) - (4, 6) - B
Теперь предположим, что вы хотите задать вопрос: полностью ли покрыто B любой комбинацией других прямоугольников.
Ответ можно сформулировать следующим образом:
- Перебрать все прямоугольники в последнем списке выше
- Если B является НЕ частью связанного прямоугольника, игнорируйте этот прямоугольник
- Если существует любой другой из исходных прямоугольников, связанных с координатами, то эта часть B покрывается этим / этим прямоугольником (ями)
- Если нет других исходных прямоугольников, связанных с координатами, то эта часть B не покрывается.
В приведенном выше примере мы видим, что 3-й и 4-й прямоугольники в окончательном списке содержат B, но также содержат другие прямоугольники, следовательно, эти части B покрыты, но последний прямоугольник в списке также содержит B, но нет другой прямоугольник, следовательно, эта часть не покрыта.
Согласно исходной диаграмме, окончательный результат будет включать прямоугольники следующим образом (буквы внутри каждого означают, какой исходный прямоугольник связан с этим новым прямоугольником):
+--+-----+----+-----+
|A |A |A |A |
| | +----+-----+-----+
| | |AC |AC |C |
| +-----+----+ | |
| |AB |ABC | | |
| | +----+-----+-----+
| | |AB |A |
+--+-----+----+-----+
|B |B |
+-----+----+
Если теперь мы по-новому взглянем на исходную диаграмму, я заштриховал части, которые найденный выше алгоритм найдет, содержит B, но никакого другого прямоугольника:
+-------------------+
|A |
| +----------+-----+
| |C | |
| +-----+----+ | |
| |B | | | |
| | +----+-----+-----+
| | | |
+--+-----+----+-----+
|#####|####|
+-----+----+
Вертикальная полоса посередине показывает, что деталь будет возвращена в виде двух прямоугольников, разделенных в этом месте, из-за способа, которым были обработаны вертикальные полосы.
Я серьезно надеюсь, что я понял себя здесь. У меня есть некоторый код, который может помочь вам с реализацией каждого прогона по спискам координат, но здесь уже 01:21 ночи, и я иду спать, но оставьте комментарий, если вы хотите увидеть какой-то реальный код для этого .
Или это было бы отличное упражнение для самостоятельной реализации:)
Вот ссылка на класс, содержащий данный метод: RangeExtensions.cs .
Этот метод является методом Slice
, просто найдите его на странице. Тип, о котором идет речь, Range - это, в основном, диапазон от одного значения к другому, поэтому в дополнение к приведенному выше алгоритму требуется немного построения и обслуживания данных.