12 KiB
Кривые Безье
Кривые Безье используются в компьютерной графике для рисования плавных изгибов, в CSS-анимации для описания процесса анимации и много где ещё.
Тему эту стоит изучить, чтобы в дальнейшем с комфортом пользоваться этим замечательным инструментом. [cut]
Виды кривых Безье
Кривая Безье задаётся опорными точками.
Их может быть две, три, четыре или больше. Например:
По двум точкам | По трём точкам | По четырём точкам |
---|---|---|
![]() |
![]() |
![]() |
Если вы посмотрите внимательно на эти кривые, то "на глазок" заметите:
- **Степень кривой равна числу точек минус один**. На рисунках выше, соответственно, получаются для двух точек -- линейная кривая (прямая), для трёх точек -- квадратическая кривая (парабола), для четырёх -- кубическая.
- **Кривая всегда находится внутри [выпуклой оболочки](http://ru.wikipedia.org/wiki/%D0%92%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D0%B0%D1%8F_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0), образованной опорными точками:**
Благодаря последнему свойству в компьютерной графике можно оптимизировать проверку пересечений двух кривых. Если их выпуклые оболочки не пересекаются, то и кривые тоже не пересекутся.
Основная ценность кривых Безье -- в том, что кривую можно менять, двигая точки. При этом кривая меняется интуитивно понятным образом.
Попробуйте двигать точки мышью в примере ниже:
[iframe src="demo.svg?nocpath=1&p=0,0,0.5,0,0.5,1,1,1" height=370]
Как можно заметить, кривая натянута по касательным 1 -> 2 и 3 -> 4.
После небольшой практики становится понятно, как расположить точки, чтобы получить нужную форму. А, соединяя несколько кривых, можно получить практически что угодно.
Вот некоторые примеры:
Математика
У кривых Безье есть математическая формула. Как мы увидим далее, в ней нет особенной необходимости, но для полноты картины -- вот она.
Координаты кривой описываются в зависимости от параметра t⋲[0,1]
- Для двух точек:
[pre]
P = (1-t)P1 + tP2
[/pre] - Для трёх точек:
[pre]
P = (1−t)2P1 + 2(1−t)tP2 + t2P3
[/pre] - Для четырёх точек:
[pre]
P = (1−t)3P1 + 3(1−t)2tP2 +3(1−t)t2P3 + t3P4
[/pre]
Эти уравнения -- векторные, т.е. вместо Pi
нужно подставить координаты i-й опорной точки (xi, yi)
.
Формула даёт возможность строить кривые, но не очень понятно, почему они именно такие, и как зависят от опорных точек. С этим нам поможет разобраться другой алгоритм.
Рисование "де Кастельжо"
Метод де Кастельжо идентичен математическому определению кривой и наглядно показывает, как она строится.
Посмотрим его на примере трех точек (точки можно двигать). Нажатие на кнопку "edit" запустит демонстрацию.
[iframe src="demo.svg?p=0,0,0.5,1,1,0&animate=1" height=370]
Алгоритм построения "де Кастельжо":
- Строятся отрезки между опорными точками 1-2-3. На рисунке выше они **чёрные**.
- Параметр `t` пробегает значения от `0` до `1`. В примере выше использован шаг `0.05`, т.е. в цикле `0, 0.05, 0.1, 0.15, ... 0.95, 1`.
Для каждого значения
t
:- На каждом из этих отрезков берётся точка, находящаяся от начала на расстоянии от 0 до `t` пропорционально длине. То есть, при `t=0` -- точка будет в начале, при `t=0.25` -- на расстоянии в 25% от начала отрезка, при `t=0.5` -- 50%(на середине), при `t=1` -- в конце. Так как **чёрных** отрезков -- два, то и точек выходит две штуки.
- Эти точки соединяются. На рисунке ниже соединяющий их отрезок изображён синим.
При `t=0.25` При `t=0.5` - На получившемся отрезке берётся точка на расстоянии, соответствующем `t`. То есть, для `t=0.25` получаем точку в конце первой четверти отрезка, для `t=0.5` -- в середине отрезка. На рисунке выше эта точка отмечена красным.
- По мере того как `t` пробегает последовательность от `0` до `1`, каждое значение `t` добавляет к кривой точку. **Совокупность таких точек для всех значений `t` образуют кривую Безье.**
Демо для четырёх точек (точки можно двигать):
[iframe src="demo.svg?p=0,0,0.5,0,0.5,1,1,1&animate=1" height=370]
Алгоритм:
- Точки по порядку соединяются отрезками: `1-2`, `2-3`, `3-4`. Получается три чёрных отрезка.
- На отрезках берутся точки, соответствующие текущему `t`, соединяются. Получается два зелёных отрезка.
- На этих отрезках берутся точки, соответствующие текущему `t`, соединяются. Получается один синий отрезок.
- На синем отрезке берётся точка, соответствующая текущему `t`. При запуске примера выше она красная.
- Эти точки описывают кривую.
Нажмите на кнопку "edit" в примере выше, чтобы увидеть это в действии.
Ещё примеры кривых:
[iframe src="demo.svg?p=0,0,0,0.75,0.25,1,1,1&animate=1" height=370]
С другими точками:
[iframe src="demo.svg?p=0,0,1,0.5,0,0.5,1,1&animate=1" height=370]
Петелька:
[iframe src="demo.svg?p=0,0,1,0.5,0,1,0.5,0&animate=1" height=370]
Пример негладкой кривой Безье:
[iframe src="demo.svg?p=0,0,1,1,0,1,1,0&animate=1" height=370]
Аналогичным образом могут быть построены кривые Безье и более высокого порядка: по пяти точкам, шести и так далее. Но обычно используются 2-3 точки, а для сложных линий несколько кривых соединяются. Это гораздо проще с точки зрения поддержки и расчётов.
[smart header="Как провести кривую через нужные точки?"] Этот вопрос не связан с кривыми Безье, но он иногда возникает в смежных задачах.
Такая задача называется интерполяцией. Существуют математические формулы, которые подбирают коэффициенты кривой по точкам, исходя из требований, например многочлен Лагранжа.
Как правило, в компьютерной графике для интерполяции используют кубические кривые, соединённых гладким образом. Вместе они выглядят как одна кривая. Это называется интерполяция сплайнами. [/smart]
Итого
Кривые Безье задаются опорными точками. Мы рассмотрели два определения кривых:
- Через математическую формулу.
- Через процесс построения де Кастельжо.
С их помощью можно описать почти любую линию, особенно если соединить несколько.
Применение:
- В компьютерной графике, моделировании, в графических редакторах. Шрифты описываются с помощью кривых Безье.
- В веб-разработке -- для графики на Canvas или в формате SVG. Кстати, все живые примеры выше написаны на SVG. Фактически, это один SVG-документ, к которому точки передаются параметрами. Вы можете открыть его в отдельном окне и посмотреть исходник: demo.svg.
- В CSS-анимации, для задания временной функции.