Алгоритм создания соседних треугольников

14

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

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

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

Пример фактического и желаемого поведения

Как я могу определить, какие 2 существующие вершины использовать при создании новых треугольников, чтобы треугольники не накладывались таким образом?

РЕДАКТИРОВАТЬ : Поиск ближайшего края дает лучшие результаты, но не идеальные. Рассмотрим эту ситуацию:

введите описание изображения здесь

Тест «ближайший край» неоднозначен и может возвращать AB или AC (поскольку ближайшая точка к X для обоих находится в точке A). Желаемый результат будет AC, чтобы сформировать треугольник ACX без наложения ребер. Как я мог обеспечить этот результат? (Я бы предпочел не выполнять отдельные тесты перекрытия ребер в качестве прерывателя связей, если это возможно, поскольку я обеспокоен тем, что тест ближайшего ребра не обязательно определит, что 2 точно равноудалены, учитывая проблемы точности с плавающей запятой.)

Kylotan
источник
Разве это не достаточно хорошо, чтобы посмотреть на последние 5 размещенных вершин и выбрать две самые близкие к вновь размещенной вершине? Я хотел бы указать вам на алгоритмы для треугольных полос ( codercorner.com/Strips.htm ), но они часто просто используют последние два или последние три, пропуская один.
Рой Т.
1
Зеленый треугольник перекрывает пурпурный? Какова цель этого? Нужно ли пользователю контролировать, где и как создаются треугольники, или приемлема триангуляция облака точек?
bummzack
Чтобы поместить это в контекст графа, по сути, вы хотите соединить свои узлы без каких-либо перекрытий ребер? (Предполагая, что пурпурный / зеленый треугольники будут иметь общий край)
MichaelHouse
Рой Т: нет - просто выбрать 2 ближайших - неправильно, как я думал на примере. Что-то неясно? Bummzack - Зеленый не пересекается с пурпурным. Цель состоит в том, чтобы сделать меш или график из этих треугольников. Пользователь нуждается в контроле, да. Байт56 - да, ребра не должны пересекаться.
Kylotan
2
Увидит ли пользователь отдельные треугольники? Или это будет одна сплошная поверхность?
Bummzack

Ответы:

11

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

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

MinAngle(newPoint, vertex, edge1, edge2)
{
   newEdgeUnit = norm(newPoint - vertex); // don't actually need to normalize this
   edge1Unit = norm(edge1 - vertex);      // you probably have these from your dist to line tests
   edge2Unit = norm(edge2 - vertex);

   edge1Dot = dot(edge1Unit, newEdgeUnit);
   edge2Dot = dot(edge2Unit, newEdgeUnit);

   // you can simply compare dot products to find the minimum absolute angle
   if (edge1Dot > edge2Dot) return edge1;     // set up this way so you can generalize to an array
   return edge2;
}

** Чтобы избежать добавления вырожденных треугольников, которые могут нарушить тест эпсилон, вы можете захотеть поместить область вокруг каждой вершины, где добавление точек запрещено, (что-то вроде запрета точек внутри некоторого кратного эпсилона, использованного выше).

Джефф Гейтс
источник
3
+1 - это ИМХО гораздо более простой ответ, чем другие, и с большей вероятностью даст правильные результаты. Расстояние до сегмента также легко вычислить с помощью интеллектуальной схемы.
Стивен Стадницки
Согласитесь, это более чистый метод. Вероятно, к чему бы я пришел, если бы думал об этом больше: /
MichaelHouse
Ах, так близко! Но, как и в ответе Byte56 и диаграмме Джимми, иногда существуют 2 равноотстоящих ребра, и одно из них нарушает ограничения. Я обновил свой вопрос.
Kylotan
@Kylotan Может быть, в этом случае просто проверить, какой из них перекрывается, и выбрать другой вариант? Найдите треугольники, разделяющие выбранное вами ребро, и проверьте, находится ли ваш новый треугольник на той же стороне этого ребра, что и существующий.
Кевин Рейд
@Kylotan Вы уверены, что ваши треугольники всегда имеют одинаковую обмотку? Если да, вы можете исключить ребро, которое имеет нормальное наведение от вашей новой вершины (используя точечный продукт).
bummzack
6

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

введите описание изображения здесь

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

Джимми привел аргумент в пользу неоднозначной точки зрения относительно того, куда пойдет новый треугольник:

неоднозначный треугольник

Это даст вам возможность выбирать между двумя действительными треугольниками. Возможно разрыв связи, центральная точка которого является самой близкой.

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

введите описание изображения здесь

MichaelHouse
источник
Возможна ситуация, когда две линии не пересекаются с ребрами (когда X ближе к вершине, чем к ребру)
Джимми
@ Джимми, ты можешь нарисовать образ такой ситуации?
MichaelHouse
Ах да, тогда у вас есть два варианта расположения треугольника! Любая из сторон будет работать. Возможно, вы можете связать разрыв с тем, у которого самое короткое расстояние до центра.
MichaelHouse
@ Kylotan это решение не работает? Вы упомянули в комментарии к Джеффу, что изображение Джимми имеет два случая, и один нарушает ограничения, но это не так. На изображении Джимми оба случая дали бы правильные треугольники, используя мой метод.
MichaelHouse
1

Имея свой пурпурный треугольник ABC, вы включаете новую вершину X. Я думаю, очевидно, что будут две прямые, начинающиеся с D, которые не будут пересекаться между какими-либо краями треугольника ABC.

Эти две линии могут быть AX & BX, BX & CX или AX & CX. Затем вы можете рассматривать вашу проблему как классическую проблему «пересекаются ли две линии»? Затем вы можете проверить, какая из этих пар линий не пересекается ни с одним из ребер треугольника ABC, следуя, например, любому из методов из этого вопроса . Следовательно, у вас будут два новых ребра нового треугольника.

Дэн
источник
Это кажется хорошим, но то, как вы это заявили, похоже, предполагает, что существует только один существующий треугольник. Как это будет обобщать для многих?
Kylotan
Хм ... если ваш X и треугольник ABC фиксированы, я думаю, что есть только один, не так ли?
Дан
Система создает новый треугольник для каждого узла после 2-го.
Kylotan
Извините, я неправильно понял ваш вопрос. Позвольте мне увидеть, как я могу расширить это на многие треугольники.
Дан
Ну, я думаю, вы могли бы искать две ближайшие вершины к X, которые не пересекают грани при подключении к X?
bummzack
1

Выяснить, находитесь ли вы в одной из однозначных областей (1, 2, 3 ниже), довольно легко: обработайте каждый край вашего треугольника как 2D-плоскость и проверьте, на какой стороне плоскости находится ваша новая точка. Если вы находитесь внутри двух из них, но снаружи одного, то этот соответствует краю треугольника, который добавляет две вершины в ваш новый треугольник.

Вороной районы треугольника

Если вы находитесь внутри одного и снаружи двух, вы находитесь в неоднозначном случае, когда ближайшая часть треугольника к вашей новой точке является углом. В этом случае вы можете сформировать 2D-плоскость из средней точки противоположного края (той, в которой вы находитесь) и ближайшей вершины (той, которая разделена между двумя плоскостями, вне которых вы находитесь). Вы можете выбрать ребро в зависимости от того, на какой стороне этой плоскости находится ваша новая точка.

Обратите внимание, что тест плоскости в 2D работает так же, как и в 3D: поставьте точку вектора из любой точки плоскости в точку с нормалью плоскости (в 2D это перпендикуляр линии).

(Между прочим, разделенные пурпурным цветом области на этом изображении называются областями Вороного; это области пространства, содержащие точки, наиболее близкие к определенному объекту - ребру или вершине - треугольника. Редактировать: моя терминология здесь на самом деле не совсем Совершенно верно, это не совсем Вороной регионы.)

Джон Калсбек
источник
Мне не сразу понятно, как это обобщается на несколько треугольников в сцене - особенно, если ближайший объект - это вершина, которая может быть разделена более чем одним треугольником.
Kylotan
@Kylotan Просто запустите алгоритм для всех треугольников и выберите общую ближайшую функцию. Вам нужна логика разрыва связи, несмотря ни на что. Если в результате вы получите ближайший объект, являющийся общей вершиной, то вы должны находиться в краевой области (# 1, # 2, # 3) только для одного треугольника, так что, может быть, вы можете выбрать это?
Джон Калсбек