И снова у меня есть вопросы по алгоритмам многоугольника.

Попробую объяснить свою проблему:

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

Наш внутренний формат многоугольника состоит из массива вершин, а многоугольник GT состоит из индексированного массива вершин, где каждое ребро представлено парой индексов.

Пример квадрата для пояснения:

Внутренний формат:

vertices[0] = Vertex2D(1,0) -> start
vertices[1] = Vertex2D(1,1)
vertices[2] = Vertex2D(0,1)
vertices[3] = Vertex2D(0,0)
vertices[4] = Vertex2D(1,0) -> end

Внешний формат:

vertices[0] = Vertex2D(1,0) 
vertices[1] = Vertex2D(1,1)
vertices[2] = Vertex2D(0,1)
vertices[3] = Vertex2D(0,0)

edges[0] = std::pair<int,int>(0,1)
edges[1] = std::pair<int,int>(1,2)
edges[2] = std::pair<int,int>(2,3)
edges[3] = std::pair<int,int>(3,0)

//There is also a BSP tree of the polygon which I don't care to depict here.

Теперь я написал алгоритм, который работает в большинстве случаев, но дает сбой и сгорает, когда два ребра имеют одну и ту же начальную вершину. Позвольте мне начать с объяснения того, как работает мой текущий алгоритм.

Создайте std :: map, где ключ является целым числом, представляющим индекс вершины. Значение представляет, где в массиве краев есть край с индексом ключа в качестве начального индекса.

Пример мокапа:

std::vector< std::pair< int, int > > edge_array;

edge_array.push_back( std::pair< int, int >( 0, 1 ) );
edge_array.push_back( std::pair< int, int >( 2, 3 ) );
edge_array.push_back( std::pair< int, int >( 1, 2 ) );
edge_array.push_back( std::pair< int, int >( 3, 0 ) );

std::map< int, int > edge_starts;
for ( int i = 0 ; i < edge_array.size(); ++i ) {
  edge_starts[ edge_array[i].first ] = i;
}

Чтобы перейти от правильного края к правильному краю, теперь я могу просто сделать следующее внутри цикла while:

while ( current_placed_index = first_index_in_polygon ) {
  int index_to_next_edge_to_be_traversed = edge_starts[ current_edge.second ];
}

Внутри этого цикла выполняется некоторая оптимизация и добавляются индексы вершин в массив.

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

Таким образом, каждый GTPolygon может привести к нескольким Polygon (внутренним) объектам.

Недостаток этого алгоритма очевиден, когда есть два ребра, которые имеют одну и ту же вершину, что и начальная вершина. Пример:

<1,2>
<1,3>
<1,5>

При прохождении моих ребер, как я узнаю, какое из этих ребер принадлежит многоугольнику, который я в данный момент пересекаю? Я мог бы попробовать обойти края НАЗАД, когда возникает такая повторяющаяся ситуация. Тогда проблема будет заключаться в возможности бесконечного перемещения туда и обратно, если во время реверсирования будет обнаружен другой дубликат.

У меня вопрос, как я могу это решить? Это вообще разрешимо? Могу ли я каким-то образом решить эту проблему с помощью дерева BSP? Количество угловых случаев немного устрашающе.

Любая помощь приветствуется, так как от этой работы зависит 5 месяцев работы.

Изменить:

Чтобы уточнить: я хочу преобразовать из индексированного представления многоугольника, с которым работает Geometry Tools, в наш внутренний формат многоугольника, который представляет собой просто серию связанных вершин в списке.

1
Nailer 11 Мар 2009 в 17:15
Можете ли вы разбить свои многоугольники мозаикой, чтобы у них всегда было 3 ребра?
 – 
Judge Maygarden
11 Мар 2009 в 17:22
Как видите, наше внутреннее представление полигонов представляет собой массив вершин. Это означает, что тесселяция не имеет смысла, поскольку все полигоны - это просто контуры. Я полагаю, что GTPolygon можно тесселировать. Вам придется объяснить, почему это может помочь, поскольку я не эксперт в этой области.
 – 
Nailer
11 Мар 2009 в 17:53
Ну, это сделало бы определение того, когда многоугольник начинается / останавливается, путем подсчета до 3 ребер ... если я не понимаю ваши вопросы.
 – 
Judge Maygarden
11 Мар 2009 в 17:55
Проблема в том, что мне нужно, чтобы результирующие полигоны были одним непрерывным контуром. Я не могу работать с треугольниками, так как наш внутренний формат многоугольника очень старомоден.
 – 
Nailer
11 Мар 2009 в 18:24
Я не совсем уверен, что должен делать ваш алгоритм. Вы просто пытаетесь конвертировать из внутреннего формата во внешний?
 – 
e.James
11 Мар 2009 в 20:27

3 ответа

Лучший ответ

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

3
Judge Maygarden 11 Мар 2009 в 22:36
Это похоже на то! Спасибо, чувак, ты действительно мне помог.
 – 
Nailer
12 Мар 2009 в 00:21

Ха-ха, хорошо, ребята. Кажется, что весь этот шум был напрасным. Я обнаружил, что у Geometry Tools есть собственный класс для решения подобных проблем.

Пример найден здесь.

1
Nailer 12 Мар 2009 в 17:37
Из любопытства (и лени) какой алгоритм поиска они используют?
 – 
Judge Maygarden
13 Мар 2009 в 06:48
На самом деле не уверен. Я не расшифровал, что на самом деле делает алгоритм. Хотя это немного отличается от DFS.
 – 
Nailer
13 Мар 2009 в 12:46
Хм, на самом деле алгоритм, который я себе придумал, дал тот же результат, что и алгоритм GT. Моя проблема была в другом. Намотка моих многоугольников была непостоянной. ОТКАЗ = D
 – 
Nailer
13 Мар 2009 в 19:27

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

0
MSN 11 Мар 2009 в 19:48
Я не контролирую порядок ребер в инструментах геометрии. Я использовал GT специально, чтобы самому не реализовывать логические операции. Ребра упорядочиваются после преобразования их из InternalPolygon в GTPolygon, но логическая операция вставляет ребра кое-где и перемешивает ребра.
 – 
Nailer
11 Мар 2009 в 19:55
Я мог бы попробовать другую внешнюю библиотеку, которая сделала бы это по-другому. Я потратил довольно много времени на поиск облегченной реализации, подобной той, что есть в GT.
 – 
Nailer
11 Мар 2009 в 19:56
Вы можете игнорировать упорядоченную часть, но вы все равно должны сохранить явное сопоставление между многоугольником и краями, которые он использует. Я предполагаю, что реальный вопрос тогда заключается в том, как преобразовать край обратно в многоугольник? Но даже это может быть неоднозначным, если вы не знаете, с какого полигона вы начали.
 – 
MSN
11 Мар 2009 в 20:38