Как я могу сложить и вычесть выпуклые многоугольники?

12

У меня есть два 2D выпуклых многоугольника, перекрывающих друг друга . Я ищу алгоритм вычитать и складывать их. Результатом должен быть один вогнутый многоугольник или (еще лучше) набор самых больших выпуклых многоугольников, образующих вогнутый результат (например, треугольники).

введите описание изображения здесь

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

Как я могу это сделать?

Себастьян Барт
источник
Мы говорим о 2D здесь? потому что в 3D комбинирование полигонов не имеет большого смысла.
concept3d
Да, извините, я говорю о 2D! Хотя я не понимаю, почему в 3D это не имеет меньшего смысла, чем в 2D.
Себастьян Барт
2
добавление двух полигонов в 3D, если они плоские, это не имеет большого смысла, если они не находятся на одной плоскости, если они имеют объем (твердые тела), тогда это другая история.
concept3d
Хорошо, я понял. Я думал не о графике, а о объектах столкновения. Спасибо за разъяснение.
Себастьян Барт
Кроме того, найдите все точки, которые они пересекают, и добавьте вершины в набор. Набор важен для предотвращения перекрытия. Затем просто добавьте все остальные вершины из двух других фигур в набор. Этот набор содержит все вершины аддитивной формы.
Вон Хилтс

Ответы:

9

TL; DR Вам необходимо реализовать логические операции с использованием BSP-деревьев.

Ну, кажется, мы говорим о Конструктивной Твердой Геометрии здесь. Я внедрил CSG на коммерческом уровне, поэтому знаю кое-что об этом.

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

Но ждать! Эта статья в основном говорит о полигональных сетках и трехмерных плоскостях, НЕТ?

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

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

Относительно числовой надежности. Хорошо отметить, что есть два типа геометрических вычислений,

  • Те, которые основаны на построении, вы строите фигуру на основе результата предыдущей операции. Например, y = sqrt(x)а затем использовать yв новой операции. Это называется конструкцией; проблема в том, что числовые ошибки будут быстро накапливаться.
  • В качестве альтернативы есть операции, в которых вместо этого используются предикаты. По сути, вместо использования конструкции вы просто спрашиваете, является ли условие истинным / ложным, и используете одно и то же значение в другой операции. Классические тесты включают в себя круг и тест на ориентацию; это также может привести к ошибкам числового типа, особенно если вы используете одинарную или двойную точность, но обычно дает гораздо лучшие результаты. Существуют другие решения, которые различаются по скорости и точности. Вот одна из недавних работ, которые избегают конструирования, используя плоскую геометрию для получения точных результатов. Я также процитирую из бумаги:

Концепция плоского представления многоугольных сеток была впервые описана Сугихарой ​​и Ири [SI89]. Этот вид представления обеспечивает одно важное преимущество, когда речь идет о задачах, которые включают изменение топологии твердых тел, представленных сетками, таких как вычисление булевых выражений: для получения результирующего многогранника не требуется создавать новую информацию о первичной геометрии.

введите описание изображения здесь

И, наконец, я хотел бы добавить, что если вы хотите начать реализацию BSP CSG, я бы рекомендовал начать с BSP Faqs .

concept3d
источник
Классно, но нелогично, учитывая, что BSP выпуклого многоугольника или многогранника - это список. Отличная статья.
3Dave
@DavidLively да, но может сделать его сбалансированным деревом, выбрав корневую плоскость, которая будет отличаться от граней. На самом деле это часть проблемы, о которой они не говорят
concept3d
Ах, это имеет смысл. Вроде гибридный BSP, тогда.
3Dave
@DavidLively также BSP не очень легко отрендерить, хотя вопрос OP является простым случаем, в более сложном случае с геометрией миллионов полигонов, когда вы закончите построение дерева, вы далеки от завершения.
concept3d
@ concept3d Я надеюсь, что это не будет слишком раздражающим, так как это 5-летний ответ, но есть две вещи, которые я действительно не понимаю: пытаясь определить, находится ли точка слева или справа от плоскости / линии, не будет ли проще просто повернуть все это так, чтобы плоскость / линия соответствовала тривиальной плоскости / линии, а затем просто рассмотреть координаты повернутой точки? Как насчет использования алгоритма Сазерленда-Ходжмана вместо деревьев BSP? Звучит очень похоже на этот подход.
Джон П
1

Исходя из вашего примера:

Выберите начальную вершину на многоугольнике A, а затем начните проверку на предмет пересечения ребер по часовой стрелке (или против часовой стрелки). Если пересечения нет, добавьте предыдущую вершину к полученному многоугольнику. Если есть пересечение, добавьте точку, в которой они пересеклись, к полученному многоугольнику, а затем начните итерацию по многоугольнику B в том же порядке намотки. Сделайте то же самое, снова поменяв местами А, если произойдет пересечение.

После того, как вы собрали все вершины для нового многоугольника, выполните для него алгоритм триангуляции. Метод ушной клипсы прост в реализации, но есть более быстрые варианты.

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

Итерация по каждому ребру для проверки пересечения будет алгоритмом O (n ^ 2). Вы можете ускорить его, сначала найдя вершины, которые находятся внутри другого многоугольника, так как ребра, связанные с этими вершинами, будут пересекающимися.

Fault
источник
0

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

введите описание изображения здесь

Выпуклость становится немного сложнее:

введите описание изображения здесь

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

В принципе:

  • Итерация по вершинам второго многоугольника.
  • Для каждой вершины V итерируйте ребра первого многоугольника:
  • Найдите «диапазон» ребер, которые обращены к вершине
  • возьмите внешнюю пару вершин, которые определяют этот диапазон, и удалите все ребра в диапазоне, который их соединяет
  • Нарисуйте два новых сегмента от этих внешних вершин до новой вершины (от второго многоугольника), убедившись, что новые ребра направлены в правильном направлении.
  • Перейдите к следующей вершине из второго многоугольника

Вот схема, иллюстрирующая процесс для первой вершины:

введите описание изображения здесь

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

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

3Dave
источник
Похоже, это решает только половину проблемы (дополнение). Также было бы полезно указать, как работают алгоритмы, или их можно оптимизировать, если полигоны перекрываются.
Алгоритм неявно игнорирует вершины, которые находятся «внутри» целевого многоугольника, что также компенсирует проблему, когда ребро второго многоугольника пересекает первый.
3Dave
Это почти равняется фазе слияния (пункт 4. алгоритма оболочки слияния . В моем случае это не правильное решение заключать в себе большую площадь после объединения полигонов. Правильным решением было бы сохранить оба полигона такими, какие они есть, поскольку они не ' не перекрывая и не трогая.
Себастьян Барт
@luftgewehrindianer Ах, да, это имеет большое значение. Возможно, я неправильно понял вопрос. Вы хотите сложить многоугольники, не беспокоясь о том, является ли результат выпуклым или вогнутым? Или создать выпуклое множество на основе пересечения? (Игнорируя вычитание на данный момент.)
3Dave
@DavidLively Представьте себе два выпуклых многоугольника одного цвета и без рамки. Когда они перекрываются, это выглядит как один новый выпуклый или вогнутый многоугольник. Он пытается найти триангуляцию комбинированной формы. Не добавляйте область между обоими полигонами.
Данияр