Задать вопрос
AlexXYZ
@AlexXYZ
O Keep Clear O

Разрезание многоугольника горизонтальными линиями. Алгоритм?

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

ce941198219f4c5690f3cb92db4b508c.png

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

Прошу помощи или совета в поиске алгоритма. Целевая программа на C++, но готов рассмотреть алгоритм и на других языках.

Update 01. исходных данных:
Направление обхода и направление точек пересечения известны.
fc6e740825a59490923128cd64694f2c.png

P.S.
По хорошему надо сохранить инфу из точек или исходные индексы этих точек после получения результата. Т.е. если алгоритм требует, например, триангуляции исходной фигуры или отображения результата в виде треугольников, то такое решение не подходит.
  • Вопрос задан
  • 51 просмотр
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 2
mayton2019
@mayton2019
Bigdata Engineer
Я-бы свел обе фигуры к объединению трапеций. Это легко сделать обходя все точки.
После чего булевы операции можно делать над трапециями.
Результат - снова объединить в фигуру.
Ответ написан
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Основаня идея простая: ориентируйте многоугольник, допустим, против часовой стрелки. Потом для каждой точки пересечения надо знать, входит ли в ней многоугольник внутрь, или выходит наружу из нужной области. Потом обходите многоугольник начиная с какой-то точки пересечения, пока отрезки снаружи - пропускаете их, пока внутри - дописываете в ответ. Надо еще помнить, где у вас последний отрезок в ответе заканчивается, так что иногда новый отрезок будет с ним не связан - это надо будет взять отрезки из прямоугольника в ответ. Но есть крайние случаи: пересечение по прямой, многоугольник выходит за границу в одной стороне, а входит в другой.

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

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

Точки будем помечать, как обработанные.

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

Потом надо будет все точки пересечения соединить в порядке вдоль прямой парами (смотрите так, чтобы удаляемая область была справа от направления движения). Их будет четное количество.

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

Удобно прямую хранить в виде Ax+By+C=0. И знак подобрать так, что точки внутри хорошей области, если их подставить в это уравнение дают положительные значения (а точки снаружи - будут отрицательные). Соответственно, проверка, что с точки можно начать обход - просто посмотреть на знак. Проверка, что есть пересечение - конец отрезка дает отрицательный знак (а потом - положительный). Точки удобно хранить в виде массива координат и массива номеров следующей точки в обходе. Никаких сишных указателей - номера следующей точки в массиве. Сортировать точки пересечения надо будет по значению Ay-Bx.

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

Это все удовольстивие будет работать за O(n log n) - потому что надо потом точки пересечения на прямой отсортировать.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы