Триангуляция. EarClip, жадная, Делоне. Код.

Продолжаем тему триангуляции.
Описываю еще 2 алгоритма и выкладываю код для всех трех.

Хотел подробно расписать код, все функции, теорию и т.д., но слишком много текста получается.
Поэтому только алгоритмы.
По коду и остальное спрашивайте в комментах.

Отмазки
Код может глючить и все такое. Я не виноват, разбирайтесь сами :)

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

Все функции — статические.
В каждом модуле 2 функции: triangulate() и test().

Режем уши
ryz.triangulation.ears.TEarClipTriangulation
Только один контур, без дырок, делает плохие треугольники. Зато быстрый и простой.

+ Пока в контуре больше 3 точек:
++ Последовательно берем 3 точки (с перехлестом через начало списка)
++ Если треугольник ориентирован по часовой стрелке:
+++ Если треугольник «пустой» (не содержит точек внутри)
++++ Сохраняем треугольник
++++ Выбрасываем среднюю точку из контура

Жадная триангуляция
ryz.triangulation.greed.TGreedTriangulation
Поддерживает дырки. Медленный.

+ Генерируем все возможные ребра
+ Сортируем по длине по возрастанию
+ Создаем список «финальных» ребер и добавляем в него контурные ребра
+ Пока список «возможных» не пуст:
++ Вытаскиваем первое ребро (самое короткое)
++ Если нет пересечения с «финальными» ребрами:
+++ Добавляем в список «финальных»
+ Сейчас надо генерировать все треугольники из ребер
+ Пока список «финальных» ребер не пуст:
++ Вытаскиваем ребро
++ Для каждого ребра в списке «финальных», которое имеет с текущим общую точку:
+++ Для каждого ребра в списке «финальных», которое соединяет два предыдущих ребра:
++++ Создаем треугольник, ориентированный по часовой стрелке
++++ Если треугольник «пустой» (не содержит точек внутри)
+++++ Сохраняем в список «промежуточных» треугольников
+ Сейчас надо выбрать только нужные треугольники (см. предыдущую статью)

Делоне
ryz.triangulation.delaunay.TDelaunayTriangulation
Поддерживает дырки. Нормальная скорость.
См. предыдущую статью.

Архив с проектом.
docs.google.com/leaf?id=0B-KnhhmWX_leMGFkYjEzOWMtZGZmZS00MzllLWE3M2QtYjY0YWMzYjJmNjQ5&sort=name&layout=list#=50
  • +6

Комментарии (9)

0
Ориентированность по часовой стрелке — отстой. Надо чтобы алгоритм сам определял чо как. (:
0
Ну, поменять не сложно.
0
Ну это же думать надо, считать… Вот пользователь нафигачил точек отбалды, я хочу их пихнуть в алгоритм и нарисовать полученные треугольники. А пользователь-то тупой, может и крест-на-крест фигачить и против часовой и вообще чёрт знает как.
0
Такую задачу в общем виде нельзя решить.
Не хватает информации, где вогнутость, где просто внутренняя точка.

Представь себе три точки, образующие треугольник и четвертую точку в центре. Это треугольник с точкой в центре или «коза»?
Когда сможешь ответить — тогда и сможешь триангулировать.
0
В первой части статьи ты как раз искал контур по пачке точек. Нужно что-то подобное, только с учётом последовательности точек (вне зависимости их напрвления) и пересечения граней контура. Типа если пользователь закрутил восьмёрку, то будет ещё учитываться точка пересечения и на выходе будет фигура из двух капелек, соединённых в одной точке. На крайняк при таких косяках искать контур вне зависимости от последовательности точек.
Вот тогда такой алгоритм можно будет использовать. А когда для использования алгоритма нужны ещё стопицот тыщь условий — это тоже круто, но область применения сильно сокращается. ):
0
Еще раз. Нам даны 8 точек, два вложенных квадрата.
На картинке 4 из множества возможных контуров.

Какой использовать?

Если мы же контур задан с учетом последовательности и проблема только в ориентации, тогда не вижу препятствий.
Определил ориентацию, провернул, если надо, и задача сводится к предыдущей.
0
Если ты порядок точек подпишешь — я тебе скажу. Вопрос не в том, что это легко или сложно, вопрос в том, что хочется готовую либу, которая умеет так, как надо, чтобы использовать не глядя. (:
0
А я хочу огромное спасибо сказать. Код очень полезный. Обязательно использую его у себя в редакторе. Спасибо =)
0
Ссылка по теме. www.splashdust.net/2009/10/box2d-mouse-drawing/
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.