Ответы:
Вот моя попытка. Следующие алгоритмы далеки от совершенства , но они просты, и я считаю, что вам следует начать с этого, проверить, работают ли они в вашей ситуации, и переключиться на что-то более быстрое и / или более точное позже.
Идея заключается в следующем:
Кривая Безье параметризуется функцией, F(t)
использующей набор контрольных точек и переменный параметр t
. Количество генерирующих очков неважно.
Линия параметризуется двумя точками A
и B
.
Пусть SAMPLES = 10
например
Начните с t0 = 0
иt1 = 1
Позволять dt = (t1 - t0) / SAMPLES
Если dt < 1e-10
(или любое другое условие точности вы посчитаете нужным), алгоритм закончен и ответF(t0)
.
Вычислить список SAMPLES + 1
точек на кривой Безье:
L[0] = F(t0)
L[1] = F(t0 + dt)
L[2] = F(t0 + 2 * dt)
L[SAMPLES] = F(t0 + SAMPLES * dt)
Найти, какая точка L
с индексом i
ближе всего к линии. Используйте любой метод расстояния между точками и линиями, который вы знаете, например, квадратное расстояние, ||AB^L[i]A||² / ||AB||²
где ^
обозначает перекрестное произведение и ||…||
является расстоянием.
Если i == 0
установить i = 1
; если i == SAMPLES
установитьi = SAMPLES - 1
Пусть t1 = t0 + (i + 1) * dt
иt0 = t0 + (i - 1) * dt
Вернитесь к шагу 3.
На этот раз у нас есть две кривые Безье, параметризованные F(t)
и G(t)
.
Пусть SAMPLES = 10
например
Начните с t0 = 0
, t1 = 1
, s0 = 0
иs1 = 1
Позволять dt = (t1 - t0) / SAMPLES
Позволять ds = (s1 - s0) / SAMPLES
Если dt < 1e-10
(или любое другое условие точности вы посчитаете нужным), алгоритм закончен и ответF(t0)
.
ЕСЛИ это первый запуск цикла:
6.1. Вычислить список SAMPLES + 1
точек F
( см. Выше ).
6.2. Вычислить список SAMPLES + 1
точек наG
.
6.3. Найдите, какая пара точек ближе всего друг к другу.
6.4. Обновление t0
, t1
, s0
, s1
как показано выше.
ELSE : в качестве альтернативы вычислить список точек на F
OR список точек G
, а затем найти какой точке F
находится ближе всего к G(s0)
и обновлению t0
и t1
, ИЛИ какая точка G
находится ближе всего к F(t0)
и обновлению s0
и s1
.
Вернитесь к шагу 3.
По своей структуре эти алгоритмы всегда будут сходиться к локальному минимуму. Тем не менее, нет никакой гарантии, что они сойдутся к лучшему решению. В частности, алгоритм кривой Безье совсем не очень хорош, и в случае, когда две кривые находятся близко друг к другу во многих местах, вы, к сожалению, можете пропустить решение в долгосрочной перспективе.
Но, как я уже сказал, прежде чем начать думать о более надежных решениях, вы должны сначала поэкспериментировать с этими простыми.
1) Переведите все на одну ось, поэтому вместо необходимости вычислять длину одной точки, «линия», «линия» - это, скажем, ось Y.
Тогда, учитывая кривую Безье, я бы сказал, что все зависит от количества контрольных точек.
Если их три (начало, «контроль» и конец), я бы сделал какое-то сканирование (скажем, каждый на пару процентов, а затем уточнил бы между ближайшими (скажем, «двоичный» подход).
Больше очков я бы опробовал пару, которая была ближе всего к (переводится по оси Y).
Я уверен, что математик может дать вам точное решение (по математике), но если вы хотите найти решение / в видеоигре, вам может быть лучше, если решение будет немного нормальным, поскольку реальное решение может содержать несколько ответов ( Я даже не говорю о вычислительной мощности).
Некоторые ответы со страницы блога Algorithmist , которая правильно находит ближайшую точку на заданной квадратичной кривой Безье.
Demo .
Для кривой Безье - случай прямой линии, наиболее точный способ найти ответ заключается в следующем: