Преобразование между кривыми Безье разной степени (порядка)

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

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

Прежде всего, я понимаю, что любое преобразование из кривой низкого порядка в кривую высокого порядка является приближением, а не эквивалентом. Я доволен "достаточно близко" в вычислительном отношении.

Во-вторых, я также понимаю, что при переходе от кривой более высокого порядка к кривой более низкого порядка происходит потеря информации. Это неизбежно, поскольку кривая более высокого порядка имеет больше «изгибов» на кривой, которые кривая более низкого порядка просто не может аппроксимировать.

Меня устраивают эти ограничения, поскольку необходимо иметь возможность добавлять и вычитать контрольные точки внутри кривой для достижения желаемой функциональности.

Мой первый вопрос связан с вопросом, заданным примерно 5 лет назад: Преобразование квадратичной кривой в кубическую кривую

Квадратичная кривая имеет три (3) контрольных точки:

Vector3 Start;
Vector3 Control1;
Vector3 End;

При преобразовании в куб вводим четвертую контрольную точку ...

Vector3 Control2;

... «Между» Control1 и End. Затем мы устанавливаем Control1 и Control2 соответственно:

Control2 = new Vector3(
    End.x + ((2.0f / 3.0f) * (Control1.x - End.x)), 
    End.y + ((2.0f / 3.0f) * (Control1.y - End.y)), 
    End.z + ((2.0f / 3.0f) * (Control1.z - End.z))
); 
Control1 = new Vector3(
    Start.x + ((2.0f / 3.0f) * (Control1.x - Start.x)), 
    Start.y + ((2.0f / 3.0f) * (Control1.y - Start.y)), 
    Start.z + ((2.0f / 3.0f) * (Control1.z - Start.z))
); 

Я не уверен, что это правильно. В этом примере был установлен только компонент «x». Я просто экстраполировал из него «y» и «z». Если это неверно, я был бы признателен за то, чтобы узнать, что правильно.

В этом примере рассматривается только преобразование квадратичных кривых в кубические. Управляющим значением при установке координат является (2.0f / 3.0f). Итак, означает ли это, что преобразование из кубической в ​​квартальную будет (2.0f / 4.0f) или (3.0f / 4.0f) или что-то совсем другое? Какова должным образом обобщенная функция этого преобразования для кривой произвольного порядка?

Мой проект также будет работать со сплайнами. Я использую метод от края до края для построения моих сплайнов, где край определяется как произвольно упорядоченная кривая от 1 (линия) до n, где первый и последний Vector3 в списке контрольных точек являются начальной и конечной точками ребро и соединяющиеся ребра разделяют конечную точку предыдущего ребра с начальной точкой следующего.

В отличие от кривых Безье, я не добавляю и не вычитаю контрольные точки. Вместо этого я разделяю и комбинирую края. Какой был бы хороший метод разделения кривой на две кривые более низкого порядка с порядком не ниже 2, приближающимся к исходной кривой? Точно так же, что было бы хорошим методом для объединения двух кривых в одну кривую высокого порядка?

Я понимаю, что это много, о чем нужно спросить в одном посте, но мне показалось, что лучше объединить все в одной теме, а не разделять ее.

Спасибо за любую помощь!


person memBrain    schedule 20.05.2017    source источник
comment
Спасибо, Майк. Думаю, это именно то, что я ищу.   -  person memBrain    schedule 20.05.2017
comment
позвольте мне превратить это в ответ, поскольку это в основном то, что есть.   -  person Mike 'Pomax' Kamermans    schedule 22.05.2017


Ответы (1)


Вы захотите прочитать http://pomax.github.io/bezierinfo/#reordering о том, как поднять кривую до более высокого порядка, что почти тривиально:

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

Это может показаться пугающим, но если вы на самом деле посмотрите, что собой представляет каждый из трех терминов, все три являются глупо простыми частями математики начальной школы. Обычно вам просто нужны новые веса, поэтому создание их в виде нового списка координат абсолютно тривиально и написано примерно за минуту. В Javascript:

function getOneHigher(x, y):
  n = x.length;
  k = n + 1;
  s = n - 1;

  let nx = [], ny =[];
  nx[0] = x[0]; nx[n] = x[s];
  ny[0] = y[0]; ny[n] = y[s];

  for (let i=1; i<n; i++) {
    nx[i] = (n*x[i] + i*x[i-1]) / k;
    ny[i] = (n*y[i] + i*y[i-1]) / k;
  }

  return {nx, ny};
}

И мы закончили. Вызов getOneHigher(x, y) приведет к получению двух массивов новых координат для одной и той же кривой, представленных кривой Безье на один градус выше, чем мы введем. Обратите внимание, что это означает, что мы сохранили набор координат кривой одинаковым (буквально: функции идентичны), уменьшая касательные в каждой координате (потому что производные не идентичны), эффективно "замедляя" все, что движется по пути, по которому идет эта кривая.

Затем вы также захотите перейти по ссылке на Замок Сирвера в том разделе, который объясняет как выполнить преобразование с потерями таким образом, чтобы минимизировать потерю информации. И это должно было быть несколько вопросов: это сайт вопросов и ответов, будущие посетители не могут найти ответы на конкретные вопросы, если вы не задаете конкретные вопросы, а вместо этого объедините несколько технически несвязанных вопросов в одном сообщении.

person Mike 'Pomax' Kamermans    schedule 22.05.2017
comment
Это определенно то, что я искал. Спасибо еще раз! - person memBrain; 31.05.2017