Соседние полигоны из списка индексов полигонов

У меня есть сетка вида this. со списком индексов, представляющих каждый многоугольник в конце. Мне нужно создать список соседних многоугольников для каждого многоугольника, и мне было интересно, знает ли кто-нибудь эффективный алгоритм для этого?

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

Нет никаких ограничений на максимальное количество индексов / вершин на многоугольник, но для простоты давайте просто примем его 3 (то есть многоугольников треугольника).

Спасибо за любую помощь! :)


person Aralox    schedule 13.01.2012    source источник
comment
Спасибо за ответы, я так и подозревал;)   -  person Aralox    schedule 13.01.2012


Ответы (3)


Ой, XML мешает :).

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

Примечание. Когда я говорю "таблица", я имею в виду "справочную таблицу".

Предположим, что каждый треугольник пронумерован и состоит из вершин v1, v2, v3, которые имеют уникальные номера и могут быть сравнены с помощью оператора ‹(чтобы мы могли получить уникальные комбинации клавиш).

Нам понадобятся две справочные таблицы:

  • Таблица edge -> (список треугольников) с именем edge_triangles.
  • Таблица «Треугольник -> (список ребер)» с именем Triangle_edges.

Таблица, которая сообщает нам, какие треугольники используют данное ребро, и другая, которая сообщает нам, из каких ребер состоит данный треугольник. Мы строим эти списки следующим образом:

for t = next triangle
    // Determine the ordering of vertices.
    min_vertex = min(t.v1, t.v2, t.v3);
    mid_vertex = median(p.v1, t.v2, t.v3);
    max_vertex = max(t.v1, t.v2, t.v3);

    // Register which edges this triangle uses.
    edge_triangles[min_vertex][mid_vertex].append(t);
    edge_triangles[mid_vertex][max_vertex].append(t);
    edge_triangles[min_vertex][max_vertex].append(t);

    // Set the edges that make up this triangle.
    triangle_edges[t].append({min_vertex, mid_vertex});
    triangle_edges[t].append({mid_vertex, max_vertex});
    triangle_edges[t].append({min_vertex, max_vertex});
for next t

Используя эти списки, мы можем взять ребра в данном треугольнике, использовать их в качестве ключа в таблице ребер и посмотреть, какие полигоны имеют это ребро. Итак, соседние треугольники. Итак, для треугольника t мы могли бы сделать следующее:

adjacent = edge_faces[face_edges[t][0]];

который является псевдокодом для «смежный равен списку треугольников, которые имеют общий 0-й край треугольника t», где 0-й - только первый.

Мы используем min, median и max, чтобы убедиться, что у нас нет разных записей для одинаковых ребер: например, {v1, v2} и {v2, v1}, где v1 и v2 - две вершины. На самом деле мы могли бы проигнорировать это и добавить «компактный» шаг, на котором мы объединяем списки, которые соответствуют разным записям в нашем списке ребер, но фактически соответствуют одному и тому же ребру.

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

  • edge -> (список ребер) таблица с именем edge_coincident_edges.

Мы используем еще одну справочную таблицу, потому что мы не можем объединить таблицу edge-> faces. Косидера, если ребра e1 и e2 смежны, e2 и e3 смежны, а e1 и e3 - нет. если бы мы объединили записи e1, e2 и e3 в списке edge-> face, вы получили бы некоторые совершенно неверные данные. Это, вероятно, немного больше, чем вы хотите сделать, но это проблема, которую я должен был решить сегодня утром :).

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

  • Таблица edge -> (первый треугольник, второй треугольник) с именем edge_triangles.

В любом случае, базовый алгоритм может быть расширен до любого числа многоугольников с любым числом ребер (не обязательно одинаковым для всех многоугольников), и это время O (N) относительно числа треугольников (или многоугольников в общем случае). Сложность пространства - O (E + N), где E - ребра, а N - количество многоугольников. Время поиска должно быть близко к O (1), если у вас есть хорошие алгоритмы хеширования.

person Liam M    schedule 13.01.2012
comment
Спасибо за это, Лиам! Это определенно поможет многим, в том числе и мне. Это сейчас ошеломляет, но я перечитаю его несколько раз, пока полностью не пойму вовлеченные процессы. - person Aralox; 27.01.2012
comment
ваш набор ребер должен быть {min_vertex, mid_vertex}, {mid_vertex, max_vertex}, {max_vertex, min_vertex}. При построении списка ребер важно соблюдать порядок, указанный в треугольнике. - person Rockcat; 14.12.2019

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

Я бы посоветовал вам прочитать статью Уэнга и Сикорски («Замечание об алгоритме линейного времени для построения графиков смежности трехмерных данных FEA», Визуальный компьютер 12: стр. 445-450, 1996). Авторы объясняют алгоритм линейного времени O (k) для поиска соседей в тетраэдрической сетке, из которого вы можете легко вывести аналогичный алгоритм для триангулированных сеток. Возможно, вы сможете распространить это и на обычные многоугольники!

Сообщите мне, работает ли это для вас!

person HopsC    schedule 23.01.2012
comment
Спасибо за ответ, это выглядит довольно напряженно! Когда я дойду до стадии, когда мне нужно повысить производительность, я обязательно попробую. - person Aralox; 24.01.2012
comment
Пожалуйста! Я работал над подобной проблемой, и действительно очень мало информации по этой конкретной проблеме (по крайней мере, с ключевыми словами, которые я использовал) ... В любом случае, рад помочь! - person HopsC; 24.01.2012
comment
@HopsC Я столкнулся с той же проблемой, см. Мой пост ниже для решения O (N), которое может обрабатывать как смежность вершин, так и истинную геометрическую смежность (с дополнительными шагами). - person Liam M; 24.01.2012
comment
@Aralox Я добавил менее дерьмовый ответ, дайте мне знать, что вы думаете - я думаю, он должен удовлетворить вашу потребность в скорости :). - person Liam M; 24.01.2012
comment
@Liam Хорошая работа :) Это похоже на работу Уэнга и Сикорски. Однако у меня есть вопрос. Там, где вы упомянули ... мы можем взять ребра в данном треугольнике, использовать это как ключ к списку ребер и посмотреть, какие многоугольники разделяют это ребро, вы имеете в виду, что для каждого ребра треугольника вы просматриваете таблицу поиска, чтобы найти соседние триады? Потому что это будет означать, что если вы выполните такую ​​процедуру для нескольких многоугольников, у вас все еще будет сложность O (N ^ 2) (когда вы просматриваете список из N строк N раз, чтобы найти соседей). ... Жажда скорости: Приятно! :) - person HopsC; 24.01.2012
comment
@HopsC Не совсем так, список должен был быть таблицей, это должны были быть эти. Вы должны взять каждое последующее ребро в треугольнике (который состоит из двух идентификаторов вершин) и найти ключ в таблице. Это должно быть амортизировано O (1) для хеш-таблицы, O (log N) для упорядоченного списка. Второго обхода нет, один раз на ребро, 3 поиска на треугольник (или ноль, если вы держите ссылку после первого поиска) дадут вам каждый соседний треугольник в простом случае. - person Liam M; 24.01.2012

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

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

person Ante    schedule 13.01.2012