Нахождение Y с учетом X на кубической кривой Безье?

Мне нужен метод, который позволяет мне найти координату Y на кубической кривой Безье с учетом координаты x.

Я встречал много мест, где мне предлагали рассматривать это как кубическую функцию, а затем пытаться найти корни, что я понимаю. ОДНАКО уравнение для кубической кривой Безье (для x-координат):

X(t) = (1-t)^3 * X0 + 3*(1-t)^2 * t * X1 + 3*(1-t) * t^2 * X2 + t^3 * X3

Что меня смущает, так это добавление значений (1-t). Например, если я заполню значения X некоторыми случайными числами:

400 = (1-t)^3 * 100 + 3*(1-t)^2 * t * 600 + 3*(1-t) * t^2 * 800 + t^3 * 800

затем переставьте его:

800t^3 + 3*(1-t)*800t^2 + 3*(1-t)^2*600t + (1-t)^3*100 -400 = 0

Я до сих пор не знаю значения коэффициентов (1-t). Как мне решить уравнение, если (1-t) все еще неизвестен?


person Captain Awesome    schedule 03.07.2012    source источник
comment
Скорее математический вопрос ...   -  person Oliver Charlesworth    schedule 03.07.2012
comment
Хорошо, лучше я спрошу математиков. Я предположил, что его использование в вычислениях будет означать, что люди здесь могут знать. Спасибо.   -  person Captain Awesome    schedule 03.07.2012
comment
Даже в 2018 году этот вопрос появляется достаточно, чтобы получить реальный ответ, поэтому я написал код для получения символического решения для этого на stackoverflow.com/a/51883347/740553, со вторым ответом, который дает неточное (но часто достаточно хорошее) решение для двоичного поиска.   -  person Mike 'Pomax' Kamermans    schedule 18.08.2018


Ответы (5)


Есть три распространенных способа выражения кубической кривой Безье.

Сначала x как функция t

x(t) = sum( f_i(t) a_i )
     = (1-t)^3 * x0 + 3*(1-t)^2 * t * x1 + 3*(1-t) * t^2 * x2 + t^3 * x3

Во-вторых, y как функция от x

y(x) = sum( f_i(x) a_i )
     = (1-x)^3 * y0 + 3*(1-x)^2 * x * y1 + 3*(1-x) * x^2 * y2 + x^3 * y3

Эти первые два математически одинаковы, просто для переменных используются разные имена.

Судя по вашему описанию, «найдите координату Y на кубической кривой Безье, учитывая координату x на ней». Я предполагаю, что у вас есть вопрос, используя второе уравнение: вы пытаетесь переставить первое уравнение, чтобы помочь вам его решить, тогда как вы должны использовать второе уравнение. Если это так, то перестановка или решение не требуется - просто вставьте значение x, и вы получите решение.

Возможно, у вас есть уравнение третьего рода, что является ужасным и трудным случаем. Оба параметра x и y являются кубической кривой Безье третьей переменной t.

x(t) = sum( f_i(t) x_i )
y(t) = sum( f_i(t) y_i )

Если это ваш случай. Дайте мне знать, и я подробно расскажу, что вам нужно сделать, чтобы решить эту проблему.

person Michael Anderson    schedule 03.07.2012
comment
Вы можете помочь мне решить параметризованную версию? У меня есть параметризованные x и y. Мне нужно y с учетом x. Так что я не знаю t, но знаю x. - person activatedgeek; 20.05.2015
comment
@activatedGeek - Вы не всегда можете решить свое дело. Может не быть решения, одно решение, много решений или даже бесконечно много решений (грустно). Лучше всего отметить, что кривая Безье гарантированно попадет внутрь выпуклой оболочки ее контрольных точек. Затем подумайте, может ли каждый сегмент CVH пересекать ваше значение x, если он сохраняет его в списке, если нет - забудьте об этом. Теперь к каждому сегменту примените разделение средней точки Безье, чтобы получить новый список сегментов Безье. Повторяйте отбрасывание и разделение, пока все сегменты не станут достаточно маленькими. Это ваши решения. - person Michael Anderson; 20.05.2015
comment
Хорошо, я бы пошел прямо к источнику. Не могли бы вы рассказать мне, как это работает? Я понимаю, как рисуют кривую слева. Я не понимаю, как можно преобразовать время анимации, чтобы сопоставить параметр t в Bezier curve, чтобы покрыть анимацию некоторым T seconds. - person activatedgeek; 20.05.2015
comment
В случае, если будущие посетители найдут этот ответ, для монотонно возрастающих кривых (кривые, которые выглядят как нормальные функции вместо того, чтобы иметь истинные вертикальные / горизонтальные касательные или изгибаться "назад" над собой), существует символическое решение, объясненное на stackoverflow.com/a/51883347/740553 - это охватывает довольно много вариантов использования, таких как анимация CSS, параметрические эквалайзеры и т. д. - person Mike 'Pomax' Kamermans; 18.08.2018

Я думаю, что это честный вопрос CS, поэтому я попытаюсь показать, как я решил это. Обратите внимание, что с данным x может быть связано более 1 значения y. В случае, когда мне это было нужно, это гарантированно не имело места, поэтому вам нужно будет выяснить, как определить, какой из них вам нужен.

Я повторил t, создав массив значений x и y. Я сделал это в достаточно высоком для своих целей разрешении. (Я хотел создать 8-битную справочную таблицу, поэтому я использовал ~ 1000 точек.) Я просто вставил t в уравнение Безье для следующих координат x и следующих y, чтобы сохранить в массиве. После того, как я сгенерировал все, я просмотрел массив, чтобы найти 2 ближайших значения x. (Или, если было точное совпадение, использовал это.) Затем я сделал линейную интерполяцию на этом очень маленьком отрезке линии, чтобы получить нужное значение y.

person user1118321    schedule 03.07.2012

Дальнейшая разработка выражения должна избавить вас от (1 - t) факторов

Если вы запустите:

expand(800*t^3 + 3*(1-t)*800*t^2 + 3*(1-t)^2*600*t + (1-t)^3*100 -400 = 0);

В wxMaxima или Maple (хотя вы должны добавить в этот параметр t), вы получите:

100*t^3 - 900*t^2 + 1500*t - 300 = 0

Решите новое кубическое уравнение для t (вы можете использовать формулу кубического уравнения для этого), после того, как у вас есть t, вы можете обнаружить, что x выполняет:

x = (x4 - x0) * t      (asuming x4 > x0) 
person higuaro    schedule 03.07.2012

Уравнение для кривой Безье (получение значения x):

Bx = (-t^3 + 3*t^2 - 3*t + 1) * P0x + 
     (3*t^3 - 6*t^2 + 3*t) * P1x + 
     (-3*t^3 + 3*t^2) * P2x + 
     (t^3) * P3x

Переставить в виде кубика т.

0  = (-P0x + 3*P1x - 3*P2x + P3x) * t^3+ 
     (3*P0x - 6*P1x + 3*P2x) * t^2 + 
     (-3*P0x + 3*P1x) * t + 
     (P0x) * P3x - Bx

Решите это, используя кубическую формулу, чтобы найти значения для t. Может быть несколько реальных значений t (если ваша кривая дважды пересекает одну и ту же точку x). В моем случае я имел дело с ситуацией, когда всегда было только одно значение y для любого значения x. Так что я смог просто взять единственный реальный корень в качестве значения t.

a = -P0x + 3.0 * P1x - 3.0 * P2x + P3x;
b = 3.0 * P0x - 6.0 * P1x + 3.0 * P2x;
c = -3.0 * P0x + 3.0 * P1x;
d = P0x;
t = CubicFormula(a, b, c, d);

Затем верните значение t в кривую Безье для y.

By = (1-t)^3 * P0x + 
     3t(1-t)^2 * P1x + 
     3t^2(1-t) * P2x + 
     t^3 * P3x
person Reuben Carter    schedule 21.03.2018
comment
Решить это с помощью кубического уравнения - хороший ответ на maths.stackexchange, но плохой ответ на вопрос о Stackoverflow C ++. Без кода, показывающего реализацию кубической формулы, это неполный ответ. - person Mike 'Pomax' Kamermans; 18.08.2018
comment
Должен ли последний член в кубической форме быть (P0x) - Bx вместо (P0x) * P3x - Bx? И формула для d будет P0x - Bx, а не только P0x? - person BoCoKeith; 13.06.2019

Итак, я искал какой-то метод, который позволил бы мне найти координату Y на кубической кривой Безье, учитывая координату x на ней.

Рассмотрим кубическую кривую Безье между точками (0, 0) и (0, 100) с контрольными точками в (0, 33) и (0, 66). Существует бесконечное количество Y для данного X. Таким образом, нет никакого уравнения, которое решало бы Y для данного X для произвольной кубической кривой Безье.

Для надежного решения вы, вероятно, захотите начать с алгоритма Де Кастельжау

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

person MrO    schedule 21.03.2013
comment
Но помните, что отсутствие общего решения не означает, что нет решений для всех случаев. Если кривая обратима, то решения, безусловно, есть, и ответ на эту проблему обсуждается в stackoverflow.com/a/51883347/740553 - person Mike 'Pomax' Kamermans; 18.08.2018