И снова у меня есть вопросы по алгоритмам многоугольника.
Попробую объяснить свою проблему:
Я использую подмножество сторонней библиотеки под названием 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, в наш внутренний формат многоугольника, который представляет собой просто серию связанных вершин в списке.
3 ответа
Фактически вы пытаетесь найти все циклы в ненаправленный граф, где каждый цикл представляет ребра уникального многоугольника. В этом документе предлагается решение для поиска в глубину (DFS).
Ха-ха, хорошо, ребята. Кажется, что весь этот шум был напрасным. Я обнаружил, что у Geometry Tools есть собственный класс для решения подобных проблем.
Пример найден здесь.
Почему бы вам не хранить полигоны явно как упорядоченный набор ребер? Это гарантирует, что для данного многоугольника вы всегда будете знать, какие ребра следует учитывать.
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .