По безье счет. Простые в использовании кривые безье

До сих пор мы обсуждали, как провести кривую через заданное множество точек. Рассмотренные методы во многих случаях дают прекрасные результаты и особенно удобны при описании формы, основа которой получена с помощью экспериментов или математических расчетов. Это, например, крыло самолета, составные части мотора, механические и структурные детали. Существует, однако, и другой класс задач, когда решение зависит как от функциональных, так и от эстетических требований, например дизайн поверхности машины, фюзеляжа самолета, формы корабля, мебели или посуды. Кроме количественных критериев здесь требуется учет практического опыта, и часто необходимо интерактивное вмешательство разработчика.

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

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

Рис. 5-25 Кривая Безье и определяющие ее точки.

Кривая Безье задается многоугольником, как показано на рис. 5-25. Так как базис Безье является бернштейновским, сразу же известны некоторые свойства кривых Безье. Например:

Функции базиса вещественны.

Степень многочлена, определяющего участок кривой, на единицу меньше количества точек соответствующего многоугольника.

Основа формы кривой повторяет очертания многоугольника.

Первая и последняя точки кривой совпадают с соответствующими точками определяющего многоугольника.

Векторы касательных в концах кривой по направлению совпадают с первой и последней сторонами многоугольника.

Кривая лежит внутри выпуклой оболочки многоугольника, т. е. внутри самого большого многоугольника, построенного по заданным точкам. На рис. 5-25 выпуклая оболочка обозначена штриховой и тонкой линиями.

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

На рис. 5-26 показано несколько четырехточечных многоугольников Безье и соответствующих кривых. На основе перечисленных выше свойств можно легко научиться предсказывать форму кривой по виду многоугольника.

Математическое параметрическое представление кривой Безье имеет вид

, , (5-62)

где базис Безье или Бернштейна, или функция аппроксимации

(5-63)

(5-64)

Это -я функция базиса Бернштейна порядка .

Рис. 5-26 Многоугольники Безье для кубических кривых.

Здесь - порядок определяющей функции базиса Бернштейна - и, следовательно, сегмента полиномиальной кривой, на единицу меньше количества точек определяющего многоугольника. Как показано на рис. 5-25, вершины многоугольника Безье нумеруются от 0 до . Поэтому и .

На рис. 5-27 изображены аппроксимирующие функции для разных значений . Заметим, что функции симметричны. Каждая функция имеет порядок , например все четыре функции на рис. 5-27b для кубические. Максимум каждой функции достигается при и равен (5-14)

. (5-65)

Рис. 5-27 Весовые функции Безье/Бернштейна. (a) Многоугольник из трех точек, ; (b) из четырех точек, ; (с) из пяти точек, ; (d) из шести точек, .

Например, для кубической кривой . Максимум и достигается в и , соответственно, и имеет значения

Рисунок 5-27b иллюстрирует этот пример.

Рассмотрим уравнения (5-62) и (5-64) для первой точки на кривой, т.е. при

, ,

, .

,

первая точка кривой совпадает с первой точкой многоугольника.

Аналогично, для последней точки кривой, т. е. при

, ,

, .

и последняя точка на кривой Безье совпадает с последней точкой определяющего многоугольника.

Рассмотрим метод построения Безье на примере.

Пример 5-7 Кривая Безье

Пусть заданы вершины многоугольника Безье , , и . Найти семь точек, лежащих на кривой Безье.

Рассмотрим уравнения (5-62) - (5-64):

,

.

В нашем случае , так как имеется четыре вершины. Отсюда

,

,

Таблица 5-4 Коэффициенты для кривой Безье

Рис. 5-28 Сегмент кривой Безье, пример 5-7.

Значения для различных значений приведены в табл. 5-4.

Точки на кривой:

,

.

Эти точки показаны на определяющем многоугольнике на рис. 5-28.

Уравнение кривой Безье можно записать в матричном виде, так же как уравнения для кубических сплайнов и параболической интерполяции (см. уравнения 5-27 и 5-44):

Здесь и .

Особенный интерес представляют матричные формы для малых значений . Для многоугольника из четырех точек кривая Безье имеет вид

.

Группируя коэффициенты, получим

. (5-68)

Аналогично, кривая Безье четвертого порядка , заданная многоугольником из пяти точек:

. (5-69)

В работе приводится обобщенное представление:

,

,

. (5-70)

Матрица - это опять . Отдельные члены матрицы таковы:

.

Уравнение (5-70) можно записать в более удобном виде

,

.

Уравнения (5-70) или (5-71) удобнее для расчета при больших значениях . Заметим, что для всех матрица симметрична относительно главной диагонали и правый нижний угол состоит из нулей.

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

Из уравнения (5-62) первая производная кривой Безье имеет вид:

. (5-72)

Вторая производная такова:

. (5-73)

Формально дифференцируя уравнение (5-63), получаем производные базисных функций

. (5-74)

Аналогично, вторые производные имеют вид:

. (5-75)

В начале и конце кривой Безье, т.е. при и , численный расчет уравнений (5-74) и (5-75) представляет затруднения.

Другой способ вычисления -й производной при :

(5-76)

. (5-77)

Отсюда первые производные в концах будут

(5-78)

. (5-79)

Это показывает, что касательные к кривой Безье в первой и последней точках параллельны соответствующим сторонам многоугольника. Аналогично, вторые производные в концах таковы:

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

Подробнее рассмотрим это на примере.

Пример 5-8 Производные кривых Безье

Рассмотрим четырехточечный многоугольник Безье, например, как на рис. 5-26 и 5-28. Вспомним представление кривой

Отсюда первая производная

Вспомним пример 5-7 и непосредственно продифференцируем базисные функции

Подставим :

Подстановка дает

Поэтому направление касательной в начале кривой совпадает с первой стороной многоугольника (см. рис. 5-28).

В конце кривой и

Аналогично, подстановка дает

и направление касательного вектора в конце кривой совпадает с последней стороной многоугольника.

Чтобы вычислить производные вдоль кривой, воспользуемся функциями базиса и уравнениями (5-74) и (5-75):

,

,

.

Результаты легко вычисляются как для , так и для . Подставляя в уравнение (5-72), получаем первую производную в любой точке кривой. Например, при имеем

Результат для точек , , , из примера 5-7 изображен на рис. 5-29.

Рис. 5-29 Кривая Безье и ее производные: ; ; .

Аналогично, вторые производные имеют вид:

,

,

,

.

Уравнение (5-73) при дает

Иллюстрация также приведена на рис. 5-29. Заметим, что вектор из начала координат в любую точку на каждой из кривых представляет соответственно направление и величину радиуса-вектора и приблизительную кривизну в этой точке на кривой.

Условие непрерывности соседних кривых Безье формулируется очень просто. Пусть кривая Безье степени задана вершинами , а соседняя кривая Безье степени - вершинами . Тогда непрерывность первой производной в точке соединения выражается соотношением

,

где - скаляр.

Рис. 5-30 Непрерывность первой производной для кубических кривых Безье.

Пользуясь уравнениями (5-78) и (5-79), получим

.

Из непрерывности кривой следует, что и

.

Отсюда направления касательных на стыке совпадают, если три вершины , , коллинеарны, т.е. должна лежать на линии между и .

Если совпадают еще и величины касательных векторов, то является серединой отрезка от до :

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

Рис. 5-31 Непрерывность второй производной для кривых Безье четвертой степени.

Для кубических кривых Безье это условие имеет вид

Несколько карандашных набросков на бумаге покажут, что данное требование существенно ограничивает множество кривых; поэтому на практике для соблюдения непрерывности вторых производных используются полиномиальные кривые более высокого порядка. На рис. 5-31 приведен пример непрерывности вторых производных для двух пятиточечных кривых Безье.

,

Здесь можно с успехом применить методику из работы . В предельном случае многоугольник сходится к кривой. Дополнительную гибкость кривой можно также получить разбиением кривой Безье на две новых таким образом, чтобы они вместе совпадали с исходной кривой. В работах Барского было показано, что любая кривая Безье может быть разбита с использованием произвольного параметра в диапазоне . Простейший случай - это средняя точка, т.е. (см. ). При разбиении средней точкой получаются два специальных вида кубических кривых Безье.

Кубическая кривая Безье (см. упражнение 5-7) задается в виде

Получаются путем приравнивания радиус-векторов и касательных векторов при , . (5-82b)

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

Мы все знаем что такое кривая. Вот несколько примеров.

Кривые Безье очень просты в использовании, и могут описывать многие формы. Кривые Безье широко используются для представления символов в шрифтах, и форм конструкций транспортных средств. Кривые Безье также используются в редакторах векторной графики для представления различных кривых, и в инструментах 3D-анимации для представления анимационных кривых.

В играх кривые Безье иногда полезны для описания пути: гоночный путь на трассе в гоночной игре, или линии в играх с рисованием линий, таких как Flight Control , или зацикленная траектория парения бабочки, что что живет в мире RPG.

Кривые Безье так популярны, потому что их математическое описания очень компактно, интуитивно понятно и элегантно. Их легко вычислить, легко использовать в более высоких измерениях (3D и выше), и могут быть соединены вместе, чтобы представить любую форму какую вы только можете себе представить.

В этом руководстве я дам вам инструкции, необходимые для реализации алгоритмов, чтобы вы смогли использовать кривые Безье в своих играх.

Математическое описание

Начнем с математики. Математически мы можем описать кривую Безье на функцию. Функция принимает параметр . Значение функции есть точка на кривой; она зависит от параметра , и от множества точек, называемых контрольными точками. Первая и последняя контрольные точки являются концами кривой. Как правило, кривая не проходит через другие контрольные точки.

Значение может колебаться от 0 до 1. Значение 0 соответствует начальной точке кривой, значение 1 соответствует конечной точке кривой. Значения в промежутке соответствуют остальным точкам на кривой.

Вот пример простейшего типа кривой Безье, отрезок:

А вот сокращенное обозначение для двух уравнений, которые дают раздельные координаты:

Точки и являются контрольными точками. Когда , правая часть уравнения равна первой контрольной точке - началу отрезка. Когда , получаем точку , вторую контрольную точку - конец отрезка.

Для более интересных форм нам нужно больше контрольных точек. Количество контрольных точек определяет степень кривой. Две контрольные точки необходимы для линейных (первая степень) кривых, таких как отрезок выше. Для второй степени, или квадратичных кривых, нам нужны три контрольные точки.

Вот формула:

Кубические кривые (или кривые третьей степени) являются наиболее часто используюемыми, и поэтому в данном руководстве мы будем обсуждать именно кубические кривые . Для их построения требуется четыре контрольные точки, и возможно вы уже хорошо знакомы с их использованием в пакетах векторной графики (да, те самые кружочки которые используются для изменения формы кривых в программах Freehand или Inkscape и есть нашими контрольными точками).

Желтые линии протянуты в том же направлении, что и касательные на концах кривой. Чем дальше расположены эти желтые сегменты, тем сильнее "натянута" кривая по направлению касательных.

Формула для кубических кривых Безье:

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

Случаи

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

Вот правильные 2D кривые Безье:

Все конечные точки на одинаковом расстоянии друг от друга. 1. Кривая без перегиба, залома или петли. 2. Кривая с перегибом, без заломов или петель. 3. Кривая с заломом. 4. Кривая с петлей. 5. Прямая линия. (В точке перегиба кривая меняет направления сгиба)

Вырожденный случай 5 является самым сложным. Могут быть следующие варианты:

  • нет перекрытий
  • кривая заламывается дважды на одном или обоих концах
  • кривая заламывается трижды тройка где-то между концами

Существует шестой случай, когда все четыре контрольные точки совпадают: в результате кривая вырождается в одну точку. Обратите внимание, что кривая не вырождается в точку когда только конечные точки совпадают - все четыре контрольные точки должны совпадать. Кому интересны технические подробности могут почитать A Geometric Characterization of Parametric Cubic Curves (1.6 MB PDF) авторов Stone и De Rose. Статья Inflection points of a cubic Bezier объясняет, как вычислить точки перегиба, а также предоставляет интерактивные апплеты Java для наглядной иллюстрации.

В 3D, петли и переломы доставляют меньше проблем, так как они проявляются только в том случае, когда все точки лежат в одной плоскости. В 3D всегда можно изменить направление движения прямой (особенно для таких случаев как 2, 4 и 5).

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

Реализация

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

Код приводится на языке C#, но перевести на Java, C + + и большинство других языков не должно принести особых проблем.

(Следующие функции будут работать и в 2D, если Vector3 заменить на Vector2.)

Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { float u = 1 – t; float tt = t* t; float uu = u* u; float uuu = uu * u; float ttt = tt * t; Vector3 p = uuu * p0; //first term p += 3 * uu * t * p1; //second term p += 3 * u * tt * p2; //third term p += ttt * p3; //fourth term return p; }

Рисование кривых Безье

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

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

for (int i = 0 ; i <= SEGMENT_COUNT; ++ i) { t = i / (float ) SEGMENT_COUNT; Vector3 pixel = CalculateBezierPoint(t, p0, p1, p2, p3) ; DrawPixel(pixel) ; //assume this function can handle Vector3 }

Этот подход страдает от следующих проблем:

Более продвинутые алгоритмы используют адаптивный прирост чтобы преодолеть эти проблемы. Сглаживание (antialiasing) кривой даст вообще класный результат, делая кривую очень гладкой и четкой. Хорошим источником для рисования кривых (и еще куча полезных тем) является Computer Graphics and Computer Modelling от David Salomon.

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

q0 = CalculateBezierPoint(0 , p0, p1, p2, p3) ; for (int i = 1 ; i <= SEGMENT_COUNT; ++ i) { t = 1 / (float ) SEGMENT_COUNT; q1 = CalculateBezierPoint(t, p0, p1, p2, p3) ; DrawLine(q0, q1) ; q0 = q1; }

Так как теперь нам не нужно волноваться о пропуске пикселей, можно выбрать больший прирост и снизить нагрузку на отрисовку. Но все же трудно выбрать приращение должным образом.

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

Вот алгоритм:

На рисунке ниже показан рабочий пример.

1. Начнем с двух конечных точек и точкой между ними. Мы проверяем угол, образованный между двумя отрезками. Он достаточно мал, поэтому мы добавим между ними точку отрисовки. 2. Затем мы делаем то же самое для левой части кривой. В этом случае угол достаточно велик, так что мы не добавляем точку, и не разбиваем дальше. 3. Мы делаем то же самое для правой части кривой. В этом случае угол достаточно мал, поэтому мы добавляем новые точки для отрисовки, и развиваем отрезок. 4. И 5. Мы делаем то же самое для двух половинок на предыдущем шаге. В каждом случае угол достаточно велик, так что новые точки не добавляются, разбиение также не нужно. 6. Окончательный набор точек используется для рисования кривой.

Ниже приведен код рекурсивного алгоритма. Хитрость в том, чтобы вставлять точки в нужном месте в списке так, что они остаются в правильном для отрисовки порядке. Мы проверяем скалярное произведения нормированных сегментов, вместо проверки угла непосредственно. Именно поэтому для сравнения используется >, вместо < как если бы мы проверяли углы напрямую.

//returns the number of points added. int FindDrawingPoints(float t0, float t1, int insertionIndex, List pointList) { tMid = (t0 + t1) / 2 ; p0 = bezierCurve(t0) ; p1 = bezierCurve(t1) ; if (p0 – p1. sqrMagnitude < MINIMUM_SQR_DISTANCE) { return 0 ; } pMid = bezierCurve(tMid) ; leftDirection = (p0 – pMid) . Normalised ; rightDirection = (p1 – mMid) . Normalised ; if (Dot(leftDirection, rightDirection) > threshold) { int pointsAddedCount = 0 ; pointsAdded += FindDrawingPoints(t0, tMid, insertionIndex, pointList) pointList. insert (insertionIndex + pointsAdded, pMid) ; pointsAdded++; pointsAdded += FindDrawingPoints(tMid, t1, insertionIndex + pointsAdded, pointList) ; return pointsAdded; } return 0 ; }

Следующая функция демонстрирует вызов рекурсивной функции:

void FindPoints() { List pointList = new List() ; p0 = bezierCurve(0 ) ; p1 = bezierCurve(1 ) ; pointList. Add (p0) ; pointList. Add (p1) ; int pointsAdded = FindPoints(0 , 1 , 1 , pointList) ; assert(pointsAdded + 2 == pointsList. Count ) ; //sanity check }

Несколько замечаний:

  • Проверка на минимальное расстояние необходима для предотвращения проблем с нормализацией очень коротких векторов. Она также предотвращает ненужные вычисления.
  • Пороговое значение на удивление близко к -1. Для старта неплохо начать с -0,99.
  • Алгоритм не очень хорошо работает для кривых, которые содержат перегибы или петли. Ниже приведен пример того, что может произойти, если применить его к кривой с перегибом.

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

Склейка кривых вместе: пути Безье

Когда мы хотим построить сложную кривую, у нас есть два варианта:

  • использовать одну кривую Безье с высокой степенью;
  • разделить кривую на более мелкие сегменты, и использовать кривые Безье низкой степени для каждого сегмента.

Последний тип кривой называется пути Безье. Пути Безье, как правило, более просты и эффективны в использовании, чем кривые высокой степени, поэтому именно этот метод здесь и описывается.

Приведенная здесь реализация является лишь одной из многих возможных. Мы определим класс, который создает список контрольных точек кривых Безье, которые составляют путь Безье. Поскольку сегменты связаны концом-к-концу, начальная и конечная точка соседних кривых совпадают, таким образом мы можем избежать дублирования точек. На рисунке показан пример пути Безье составленого из четырех кривых Безье. В этом случае, список содержит 13 точек, как показано на рисунке слева.

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

class BezierPath { List controlPoints; Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { ... } List GetDrawingPoints() { List drawingPoints = new List() ; for (int i = 0 ; i < controlPoints. Count - 3 ; i+= 3 ) { Vector3 p0 = controlPoints[ i] ; Vector3 p1 = controlPoints[ i + 1 ] ; Vector3 p2 = controlPoints[ i + 2 ] ; Vector3 p3 = controlPoints[ i + 3 ] ; if (i == 0 ) //Only do this for the first endpoint. //When i != 0, this coincides with the end //point of the previous segment { drawingPoints. Add (CalculateBezierPoint(0 , p0, p1, p2, p3) ) ; } for (int j = 1 ; j <= SEGMENTS_PER_CURVE; j++ ) { float t = j / (float ) SEGMENTS_PER_CURVE; drawingPoints. Add (CalculateBezierPoint(t, p0, p1, p2, p3) ) ; } } return drawingPoints; } }

Данный рекурсивный алгоритм легко адаптируется для получения промежуточных точек. Пример вы можете найти в прилагаемом к статье коде.

При реализации путей Безье, вы можете сделать вашу жизнь намного проще, выполнив следующие действия:

  • Включить отладку режимов для рисования контрольных точек, конечных точек Безье, рисование точек и касательных.
  • Вывести число точек отрисовки и контрольных точек: благодаря этому вы всегда сможете проверить сколько точек генерирует алгоритм, и вменяемость этого количества.

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

  • Большинство 3D движков требуют использовать короткие прямые линии для рендеринга кривых, поэтому вы должны точно представлять себе ценность внедрения отрисовки кривых Безье.
  • Когда движение находится под контролем физики, соответственно резкие изменения скорости и направления практически отсутсвуют. Объекты, как правило, перемещаются путем изменения силы, действующей на объект, и благодаря этому их скорость не может измениться мгновенно. Таким образом, любое движение сглаживается автоматически: любой объект следующий вдоль соединенных прямых линий будет автоматически следовать сглаженому пути - в кривых Безье нет никакой надобности.

Скачать

  • Bezier Curves (64 KB, Unity 3D Project, zipped)
  • BezierPath.cs (C# source code file)

Статья является переводом, ссылка на источник - Bezier Curves for your Games: A Tutorial .
Если вы заметите какие либо неточности в переводе - просьба сообщать об этом письмом на адрес указаный внизу страницы.

Простая и понятная реализация известных кривых Безье на C#.

Введение

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

Краткие сведения

Кривые Безье - параметрические кривые, в значительной степени настраиваемые и гладкие, хорошо подходят для многих задач. Они были названы в честь Пьера Безье, французского математика и инженера, разработавшего данный метод компьютерного черчения в конце 1960 г. во время работы в автомобилестроительной фирме Рено. Говорят, что одновременно такая же разработка возникла в ходе исследования Форда. До сих пор неясно, кто первым создал их.

В статье в основном делается упор на интерполяции и вычерчивании кривых. При интерполяции нужно найти неизвестные токи, используя известные значения. Набор дискретных точек можно представить в виде непрерывной структуры, получив строго определенную кривую для отсутствующих точек. Кривая инициализируется определенными базовыми точками и пытается сгенерировать новые точки, приближающие (или интерполирующие) старые значения.

Алгоритм построения кривой Безье

Рассмотрим n +1 точек P 0 ,…,P n и соединим точки в ломаную линию, называемую далее контрольным полигоном.

При наличии точек P i , i = 0,...,n , наша задача – определить кривую g (t ) для всех значений t ? . Идея показана ниже:

Основной алгоритм

Здесь цель – найти точки в середине между двумя соседними точками и повторять это до тех пор, пока все повторы не будут исчерпаны. Новые значения точек дадут кривую. Известное уравнение Безье – точная формулировка данной идеи. Here is the algorithm:

Шаг 1: Выбрать значение t ? . Это значение не меняется на всех остальных шагах.

Шаг 2: Установить P i (t ) = P i , для i = 0,...,n .

Шаг 3: Длч j = 0,...,n , установить для i = j ,...,n .

Шаг 4: g (t ) = P n (t )

Частный и общий случаи

Здесь будут даны формулы для общего и частного случаев, полезные в определенных применениях. Код в статье не показывает ни одну из них, но он использует обобщенную формулу. Начнем с обобщенной формулы:

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

Это уравнение является лишь формулировкой вышеуказанного алгоритма (итерации по средним точкам). Немаловажно, что весь алгоритм может быть сведен в формулу, и непосредственная реализация может дать правильные результаты. Здесь n обозначает количество точек, а P обозначает сами точки. Факториальные коэффициенты точек называются базисными функциями Бернштейна, по имени их создателя.

Здесь частные случаи:

Линейный Безье:

Квадратичный Безье:

Безье третьей степени:

Объяснение и использование кода

Это функция, делающая всю работу. Она очень короткая и очень простая. Так как мы имеем дело только с двумерными кривыми, точки имеют только координаты X и Y . Функция вычисляет точки Безье.

Public void Bezier2D(double b, int cpts, double p)
{
int npts = (b.Length) / 2;
int icount, jcount;
double step, t;

// Вычисляем точки на кривой

Icount = 0;
t = 0;
step = (double)1.0 / (cpts - 1);

For (int i1 = 0; i1 != cpts; i1++)
{
if ((1.0 - t) < 5e-6)
t = 1.0;

Jcount = 0;
p = 0.0;
p = 0.0;
for (int i = 0; i != npts; i++)
{
double basis = Bernstein(npts - 1, i, t);
p += basis * b;
p += basis * b;
jcount = jcount +2;
}

Icount += 2;
t += step;
}
}

Остальные функции – лишь вспомогательные функции, участвующие в факториальных вычислениях и расчетах базисных функций, являющихся довольно тривиальными. Чтобы правильно использовать данную функцию, передайте ей набор точек в формате: XYXYXYXYXYXYXYXYXYXY.... координаты, и сколько точек вам нужно рассчитать на кривой. Функция заполнит массив p точками траектории.

Из-за ограничений факториальных вычислений код рассчитывает кривые только до 32 точек. Более сложные конструкции обычно представляются с помощью комбинации данных кривых (как в Adobe Photoshop , Illustrator и Flash – инструмент траектории).

Хотя GDI (интерфейс графических устройств) имеет встроенную функцию расчета кривой Безье, для обучения нежелательно использовать встроенные библиотеки. GDI не всегда сможет делать работу за вас! Где-то, когда-то, вам может понадобиться реализовать ее, и к тому времени вы должны примерно представлять, как работают эти кривые.

радиус-вектора B -кривой

    Фиксируем t . Положим Тогда существует единственное такое, что где

    Для определенного выше индекса если вычисляем единственное ненулевое значение ненормированного B -сплайна первого уровня (m=1) :

    Напомним, что было выбрано на первом шаге, так чтобы При этом, в силу условия знаменатель а в силу условия имеем Следовательно, Для индекса находящегося вне множества значение не вычисляется.

    С помощью соотношений Кокса - де Бура вычисляем все отличные от нуля в точке ненормированные сплайны -го порядка при :


    В частности,

    (6.6)

    где Положив в (6.6) получим

    Лемма 6.5 . Имеет место соотношение :

  1. Вычисляем нормированные сплайны для каждого по формуле (при этом ).

  2. Окончательно вычисляем по формуле

Алгоритм де Бура вычисления радиус-вектора B-кривой

Теорема 6.4 . Радиус-вектор r(t) B -кривой:

может быть вычислен с помощью следующего алгоритма:

Данный алгоритм иллюстрируется следующей диаграммой ():

Поверхности, определяемые матрицами опорных точек и весов

Поверхности Безье

Определение 6.2.1 . Пусть дано (m +1) * (n+1) точек в пространстве образующих прямоугольную матрицу (сетку Безье):

Поверхностью Безье порядка m * n , соответствующей сетке называется поверхность

(6.7)

где E - оператор сдвига вперед по первому индексу, F - оператор сдвига вперед по второму индексу:

Операторы E и F очевидно коммутируют друг с другом: Поэтому т. е. формула (6.7) непротиворечива.

Определение 6.2.2 . Рациональная поверхность Безье, построенная по точкам с весами определяется следующим образом:

(6.8)

Формула (6.8) означает, что мы строим поверхность Безье в по точкам а затем применяем преобразование

Задача 6.2.1 . Наглядно изучить влияние опорных точек и их весов на рациональную поверхность Безье, меняя исходные данные pts (опорные точки) и (их веса) в нижеследующей программе. В матрице весов стоят двумерные векторы, но используется только их первая компонента. Вторая компонента фиксирована. Это связано с неспособностью Mathematica применять функцию BezierFunction к матрицам из скаляров.

Пример 6.2.1 . Рациональная поверхность Безье с возможностью непосредственного управления весами с помощью движков.

In: = DynamicModule [ {pts, a, w0, pw, w, g, f, w6, w7, wl0, wll, i, j, out, ins, u, v, n, pts0}, pts = {{{0, 0, 0}, {0, 1, 0), {0, 2, 0}, {0, 3, 0}}, {{1, 0, 0}, {1, 1, 1}, {1, 2, 1}, {1, 3, 0}}, {{2, 0, 0}, {2, 1, 1}, {2, 2, 1}, {2, 3, 0}}, {{3, 0, 0}, {3, 1, 0}, {3, 2, 0} , {3, 3, 0}}}; pts0 = Flatten ; n = Length ; Row[ {Manipulate ] , {i, 1, 4}, {j, 1, 4}]; pw = Table ] pts [ ] , {i , 1, 4} , { j , 1, 4} ] ; g = BezierFunction; f = BezierFunction; Show[{Graphics3D[{PointSize, Red, Map , Green, Text , pts0[[#]] + {0.01, 0.04, 0.04}] & /@ Range[n]}], Graphics3D[{Gray, Dashed, Line, Line]}], ParametrioPlot3D / g , {u, 0, 1}, {v, 0, 1}, PlotStyle -> FaceForm ] }] , Column[{Control[{{ins, Green, "Внутренний цвет"}, Green}], Control[{{out, Red, "Внешний цвет"}, Red}]}, Right], {{w5, 10}, 1, 100}, {{w6, 10}, 1, 100}, {{w9, 10}, 1, 100}, {{wl0, 10}, 1, 100}] MatrixForm } , " " ] , Initialization: -> (pts = {{{0, 0, 0}, {0, 1, 0}, {0, 2, 0}, {0, 3, 0}}, {{1, 0, 0}, {1, 1, 1}, {1, 2, 1}, {1, 3, 0}}, {{2, 0, 0}, {2, 1, 1}, {2, 2, 1}, {2, 3, 0}}, {{3, 0, 0}, {3, 1, 0}, {3, 2, 0}, {3, 3, 0}}}; pts0 = Flatten ; a = 1; n = Length)]


Геометрический смысл поверхности Безье

Поверхность Безье можно получить следующим образом:

При этом соответствующий оператор перехода от опорной точки, взятой на кривой к следующей опорной точке, взятой на кривой в терминах узлов сетки pij описывается оператором сдвига F по второму индексу. Следовательно,

где m и n - количество шагов по первому и второму индексу соответственно, начиная от угловой точки сетки Безье, 00 - индекс этой угловой точки, с которой мы начинаем образовывать все остальные узлы сетки операторами сдвига E и F . Имеем

(6.9)

(6.10)

Здесь через обозначены четырехугольные листы Безье , построенные из точек p ij, взятых в качестве угловых точек, аналогично формуле (6.9). может быть получена с помощью следующего алгоритма:

Полученная точка и будет точкой с параметрами на рациональной поверхности Безье, построенной по

Деление поверхности Безье

Деление поверхностей Безье целиком основано на делении кривых Безье. Как мы уже знаем, каждая из кривых Безье (обычных или рациональных), построенных по столбцам сетки опорных точек может быть разделена в параметрической точке без изменения ее формы. При таком делении получаются две поверхности Безье (составляющие вкупе исходную поверхность) и соответствующие им две матрицы опорных точек Безье, каждая из которых имеет тот же порядок, что и исходная матрица: и Затем, каждую из получившихся двух поверхностей Безье надо поделить в параметрической точке (с помощью деления кривых Безье, построенных по строкам соответствующих матриц). В итоге получится четыре поверхности Безье и соответствующие им четыре матрицы опорных точек: и Эти четыре поверхности Безье будут лежать на исходной поверхности Безье, делить ее на четыр е части и в совокупности составлять исходную поверхность.

Новые сети опорных точек и получаются из исходной сети по следующим формулам, аналогичным формулам (5.26):




Понравилась статья? Поделитесь с друзьями!