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


14

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

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

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

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

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

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

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

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


Разве это не достаточно хорошо, чтобы посмотреть на последние 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 ближайших ребер).

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

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

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

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

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

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

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


Возможна ситуация, когда две линии не пересекаются с ребрами (когда 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) только для одного треугольника, так что, может быть, вы можете выбрать это?
— Джон Калсбек
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.