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


14

У мене є система, де можна клацнути один раз, щоб розмістити вузол у сцені. Розміщуючи 3 вузли, він утворює трикутник. Розміщуючи будь-які майбутні вузли, він створює новий трикутник, приєднуючи цей вузол до двох найближчих існуючих вузлів.

Це працює чудово більшу частину часу, але є помилковим при використанні поблизу трикутників з дуже гострими кутами, оскільки один з 2 найближчих вузлів часто не той, який слід використовувати.

Наприклад, дивіться зображення нижче. Перший розміщений пурпуровий трикутник. Якщо потім натисніть на позицію з позначкою X, я отримаю новий трикутник, де знаходиться синя накладка. Те, що я хочу, - це новий трикутник, де є зелена накладка. (тобто симетричний до пурпурового в цьому прикладі. Пояснення: Зелений та пурпуровий трикутники не перетинаються - зелений поширюється під синім до самого лівого вузла)

Приклад фактичної та бажаної поведінки

Як я можу визначити, які 2 існуючі вершини використовувати при створенні нових трикутників, щоб трикутники не накладалися так?

EDIT : Пошук найближчого краю дає кращі результати, але не ідеальні. Розглянемо цю ситуацію:

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

Тест "найближчого краю" неоднозначний і може повертати AB або AC (оскільки найближча точка до X для обох знаходиться в A). Бажаним результатом буде зміна, щоб утворити трикутник ACX без ребер, що перетинаються. Як я міг забезпечити цей результат? (Я краще не повинен проводити окремі випробування на перекриття крайок як перемикач крайок, якщо це можливо, оскільки я стурбований тим, що найближчий тест з краєм не обов'язково помітить, що 2 точно рівновіддалені, враховуючи питання точності з плаваючою точкою.)


Чи не досить добре подивитися останні 5 розміщених вершин і вибрати дві найближчі до щойно розміщеної вершини? Я хотів би вказати на алгоритми для трикутних смуг ( codercorner.com/Strips.htm ), але вони часто використовують лише останні два або три останні пропускаючі.
Рой Т.

1
Чи зелений трикутник перекривається пурпуровим? Яка мета цього? Чи потрібен користувачеві контроль над тим, де і як створюються трикутники, чи було б прийнятним триангуляція хмари точок?
bummzack

Щоб помістити це в контекст графа, по суті, ви хочете з'єднати свої вузли, не перекриваючи ребра? (Припускаючи, що пурпуровий / зелений трикутники поділять край)
MichaelHouse

Рой Т: ні - просто вибрати 2 найближчих - це неправильно, як я вважав, що показує приклад. Щось незрозуміле? Bummzack - Зелений не перетинається з пурпуровим. Мета - зробити сітку або графік з цих трикутників. Користувачеві потрібен контроль, так. Байт56 - так, жоден край не повинен перетинатися.
Кілотан

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;
}

** Щоб уникнути додавання вироджених трикутників, які можуть порушити тест epsilon, ви можете поставити область навколо кожної вершини, де додавання точок заборонено (щось на кшталт заборони точок у межах декількох кращих епсилону, що використовується вище).


3
+1 - це ІМХО набагато простіша відповідь, ніж інші, і швидше за все дасть правильні результати. Відстань до сегмента легко обчислити також за допомогою розумної схеми.
Стівен Стадницький

Домовились, це більш чистий метод. Напевно, до чого б я прийшов, якби подумав про це більше: /
MichaelHouse

Ах, так близько! Але, як і у відповіді Byte56 та діаграмі Джиммі, іноді є 2 рівновіддалених ребра, і один з них порушує обмеження. Я оновив своє запитання.
Килотан

@Kylotan Можливо, у такому випадку просто перевірити, яке з них перекривається, і скористатися іншим варіантом? Подивіться на трикутники, які ділять вибране вами ребро, і перевірте, чи є ваш новий трикутник на тій же стороні цього краю, що і існуючий.
Кевін Рейд

@Kylotan Ви впевнені, що у ваших трикутників завжди однакова обмотка? Якщо так, ви можете виключити край, який має звичайний вказівник від вашої нової вершини (використовуючи крапковий продукт).
bummzack

6

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

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

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

Джиммі висунув справу з точки зору, що є неоднозначним щодо того, куди піде новий трикутник так:

неоднозначний трикутник

Це дасть вам можливість вибрати між двома дійсними трикутниками. Можливо, розрив краватки є центром, який знаходиться найближче.

Зважаючи на ваше оновлення, але більш складне, моє рішення призведе до крапки лише тоді, коли у вас є два дійсні трикутники. Використовуючи цей метод, ваш другий приклад зображення дасть бажаний результат.

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


Можлива ситуація, коли дві лінії не перетинаються з ребрами (коли X ближче до вершини, ніж до краю)
Джиммі

@Jimmy, ти можеш намалювати таку ситуацію?
MichaelHouse


Ага так, тоді у вас є два варіанти, куди поставити трикутник! Будь-яка сторона працювала б. Можливо, ви можете зв'язати перерву з тією, яка має найменшу відстань до центру.
MichaelHouse

@Kylotan це рішення не працює? Ви згадали в коментарі Джеффу, що в зображенні Джиммі є два випадки, і один порушує обмеження, але це неправда. За зображенням Джиммі, обидва випадки створювали би дійсні трикутники, використовуючи мій метод.
MichaelHouse

1

Маючи пурпуровий трикутник ABC, ви включаєте нову вершину X. Я думаю, очевидно, що на D буде дві лінії, які не будуть перетинатися між будь-яким із ребер трикутника ABC.

Ці два рядки можуть бути AX & BX, BX & CX або AX & CX. Тоді ви можете ставитися до своєї проблеми як до класичної проблеми "чи перетинаються дві лінії"? Потім можна перевірити, яка з цих пар прямих не перетинається з будь-яким із ребер трикутника ABC, слідуючи, наприклад, за будь-яким із методів цього запитання . Значить, у вас вийдуть два нові краї нового трикутника.


Це здається гарним, але, як ви заявили, здається, існує лише один існуючий трикутник. Як би це узагальнити для багатьох?
Кілотан

Гум ... якщо ваш X і ваш трикутник ABC є фіксованими, я думаю, є лише одна, чи не так?
День

Система створює новий трикутник для кожного вузла після 2-го.
Kylotan

Вибачте, я неправильно зрозумів ваше запитання. Дозвольте мені побачити, як я можу поширити це на багато трикутників.
День

Я гадаю, ви могли шукати дві найближчі вершини до X, які не перетинають жодного краю, коли підключено до X?
bummzack

1

Зрозуміти, чи знаходитесь ви в одній з однозначних областей (1, 2, 3 нижче), досить просто: обробіть кожен край вашого трикутника як двовимірну площину і випробуйте, на якій стороні площини знаходиться ваша нова точка. Якщо ви знаходитесь у двох із них, але поза однією, то цей відповідає краю трикутника, який вносить дві вершини у ваш новий трикутник.

Вороної області трикутника

Якщо ви знаходитесь в одному і зовні двох, ви знаходитесь у неоднозначному випадку, коли найближча частина трикутника до вашої нової точки - кут. У цьому випадку ви можете сформувати 2D площину від середини протилежного краю (тієї, що ви знаходитесь всередині) та найближчої вершини (тієї, що розділяється двома площинами, які ви знаходитесь поза). Ви можете вибрати край залежно від того, на якій стороні цієї площини знаходиться ваша нова точка.

Зверніть увагу, що тест на площину в 2D працює так само, як і в 3D: нанесіть вектор з будь-якої точки на площину до вашої точки з нормою площини (у 2D це перпендикуляр лінії).

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


Мені не відразу зрозуміло, як це узагальнюється на кілька трикутників на сцені - особливо, якщо найближчою ознакою є вершина, яку може ділити більше 1 трикутника.
Килотан

@Kylotan Просто запустіть алгоритм для всіх трикутників і виберіть загальну найближчу функцію. Вам потрібна певна логіка розриву зв'язків, незважаючи ні на що. Якщо ви переконаєтеся, що найближча функція є спільною вершиною, то вам слід опинитися в крайовому регіоні (№1, №2, №3) лише для одного трикутника, тож, можливо, ви можете вибрати це?
Джон Калсбек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.