Кривые Безье: квадратичные и кубические

Кривые Безье — фундаментальный инструмент векторной графики, используемый для построения гладких и управляемых линий. В библиотеке Two.js они лежат в основе большинства сложных форм и контуров. Кривая задаётся набором контрольных точек, положение которых определяет её форму.

Существует два наиболее распространённых типа:

  • Квадратичные кривые Безье (quadratic)
  • Кубические кривые Безье (cubic)

Оба типа активно применяются в Two.js при работе с путями (Two.Path) и сегментами (Two.Anchor).


Квадратичная кривая Безье

Математическая модель

Квадратичная кривая определяется тремя точками:

  • начальная точка ( P_0 )
  • контрольная точка ( P_1 )
  • конечная точка ( P_2 )

Формула:

[ B(t) = (1 - t)^2 P_0 + 2(1 - t)t P_1 + t^2 P_2, t ]

B(t) = (1 - t)^2 P_0 + 2(1 - t)t P_1 + t^2 P_2

Контрольная точка влияет на «изгиб» кривой, но сама не лежит на ней.


Представление в Two.js

В Two.js каждая точка пути представлена объектом Two.Anchor. Для квадратичной кривой используется одна управляющая точка (handle), обычно задаваемая через свойства:

  • controls.left
  • controls.right

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

Пример создания квадратичной кривой:

const two = new Two({ width: 500, height: 500 }).appendTo(document.body);

const path = new Two.Path([
  new Two.Anchor(50, 250),
  new Two.Anchor(250, 50),
  new Two.Anchor(450, 250)
], false, false, true);

path.stroke = 'black';
path.linewidth = 2;

two.add(path);
two.update();

Здесь центральная точка играет роль контрольной, формируя изгиб.


Управление кривизной

Изменение координат контрольной точки приводит к изменению формы кривой:

  • приближение к прямой → кривая становится более «плоской»
  • удаление → усиливается изгиб
  • перемещение вверх/вниз → меняется направление дуги

Кубическая кривая Безье

Математическая модель

Кубическая кривая определяется четырьмя точками:

  • начальная точка ( P_0 )
  • первая контрольная точка ( P_1 )
  • вторая контрольная точка ( P_2 )
  • конечная точка ( P_3 )

Формула:

[ B(t) = (1 - t)^3 P_0 + 3(1 - t)^2 t P_1 + 3(1 - t)t^2 P_2 + t^3 P_3]

B(t) = (1 - t)^3 P_0 + 3(1 - t)^2 t P_1 + 3(1 - t)t^2 P_2 + t^3 P_3

Две контрольные точки дают значительно больше гибкости по сравнению с квадратичной кривой.


Представление в Two.js

В Two.js каждая точка (Two.Anchor) может иметь два управляющих вектора:

  • controls.left — входящая ручка
  • controls.right — исходящая ручка

Пример:

const a = new Two.Anchor(100, 300);
const b = new Two.Anchor(400, 300);

a.controls.right.set(100, -200);
b.controls.left.set(-100, -200);

const path = new Two.Path([a, b], false, false, true);

path.stroke = 'blue';
path.linewidth = 3;

two.add(path);
two.update();

Здесь:

  • a.controls.right задаёт первую контрольную точку
  • b.controls.left задаёт вторую

Геометрическая интерпретация

Кривая всегда:

  • начинается в ( P_0 )
  • заканчивается в ( P_3 )
  • направлена в сторону ( P_1 ) в начале
  • направлена в сторону ( P_2 ) в конце

Это позволяет контролировать:

  • начальное направление
  • конечное направление
  • форму изгиба между ними

Сегменты и кривые в Two.Path

Объект Two.Path представляет собой последовательность точек (Anchor), соединённых линиями или кривыми.

Тип соединения определяется наличием управляющих точек:

  • нет controls → прямая линия
  • есть controls → кривая Безье

Пример смешанного пути:

const path = new Two.Path([
  new Two.Anchor(50, 250),
  new Two.Anchor(150, 150),
  new Two.Anchor(250, 250),
  new Two.Anchor(350, 150)
], false, false, true);

path.vertices[1].controls.right.set(50, -50);
path.vertices[2].controls.left.set(-50, -50);

Автоматическая интерполяция

Two.js может автоматически сглаживать кривые при помощи метода:

path.curved = true;

или:

path.smooth();

Метод smooth():

  • вычисляет управляющие точки автоматически
  • создаёт плавный переход между сегментами
  • полезен для построения органических форм

Замкнутые кривые

Замкнутый путь (closed = true) соединяет последнюю точку с первой:

const path = new Two.Path(points, true);

Особенности:

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

Визуализация управляющих точек

Для отладки и понимания поведения кривых полезно отображать:

  • сами точки
  • управляющие ручки
  • линии влияния

Пример:

const handleLine = new Two.Line(
  anchor.x,
  anchor.y,
  anchor.x + anchor.controls.right.x,
  anchor.y + anchor.controls.right.y
);

handleLine.stroke = 'red';

Параметризация кривой

Параметр ( t ) описывает положение точки на кривой:

  • ( t = 0 ) → начало
  • ( t = 1 ) → конец

Two.js не предоставляет прямого API для вычисления точки по ( t ), но это можно реализовать вручную.

Пример для кубической кривой:

function cubicBezier(t, p0, p1, p2, p3) {
  const u = 1 - t;
  return {
    x: u*u*u*p0.x + 3*u*u*t*p1.x + 3*u*t*t*p2.x + t*t*t*p3.x,
    y: u*u*u*p0.y + 3*u*u*t*p1.y + 3*u*t*t*p2.y + t*t*t*p3.y
  };
}

Разбиение кривых

Кривые можно разбивать на сегменты:

  • для анимации
  • для коллизий
  • для аппроксимации

Метод де Кастельжо:

  • рекурсивное линейное интерполирование
  • используется для точного деления кривых

Производные и касательные

Первая производная кривой даёт направление касательной.

Для кубической кривой:

[ B’(t) = 3(1 - t)^2 (P_1 - P_0) + 6(1 - t)t (P_2 - P_1) + 3t^2 (P_3 - P_2)]

Это важно для:

  • ориентации объектов вдоль пути
  • анимации движения
  • вычисления нормалей

Практическое применение в Two.js

Анимация вдоль кривой

let t = 0;

two.bind('upd ate', function() {
  t += 0.01;

  const pos = cubicBezier(t, p0, p1, p2, p3);
  circle.translation.se t(pos.x, pos.y);

  if (t > 1) t = 0;
});

Построение сложных форм

Кривые Безье позволяют:

  • рисовать иконки
  • создавать шрифты
  • моделировать органические формы

Импорт SVG

SVG использует кривые Безье (команды Q и C):

  • Q — квадратичные
  • C — кубические

Two.js корректно интерпретирует их при загрузке SVG:

two.load('shape.svg', function(group) {
  two.add(group);
});

Сравнение квадратичных и кубических кривых

Характеристика Квадратичная Кубическая
Контрольных точек 1 2
Гибкость Средняя Высокая
Сложность Низкая Выше
Использование Простые формы Сложные контуры

Оптимизация и производительность

При работе с большим количеством кривых:

  • уменьшение числа сегментов ускоряет рендеринг
  • избегание лишних управляющих точек
  • предварительная аппроксимация

Ошибки и особенности

  • резкие перегибы возникают при неправильном расположении handles
  • пересечения могут приводить к визуальным артефактам
  • несогласованные управляющие точки ломают плавность

Управление симметрией

Для плавных кривых часто требуется симметрия управляющих точек:

anchor.controls.left.copy(anchor.controls.right).multiplyScalar(-1);

Это обеспечивает:

  • гладкий переход
  • отсутствие изломов
  • непрерывную производную

Итоговая структура кривых в Two.js

  • Two.Path — контейнер
  • Two.Anchor — вершины
  • controls.left/right — управление кривизной
  • curved и smooth() — автоматизация

Кривые Безье в Two.js — это сочетание строгой математической модели и гибкого API, позволяющего строить как простые, так и сложные графические структуры с высокой степенью контроля над формой.