Сегменты и точки пути

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

Сегмент включает три ключевых компонента:

  • Точка (point) — координаты положения сегмента
  • Входящий вектор (handleIn) — влияет на кривизну перед точкой
  • Исходящий вектор (handleOut) — влияет на кривизну после точки

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


Создание сегментов

Сегменты можно создавать как вручную, так и автоматически при добавлении точек в путь.

Простейший способ через координаты:

var path = new Path();
path.add(new Point(100, 100));
path.add(new Point(200, 100));

В этом случае создаются сегменты без управляющих векторов — линия будет прямой.

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

var segment = new Segment(
    new Point(100, 100),
    new Point(-50, 0),
    new Point(50, 0)
);

var path = new Path();
path.add(segment);

Здесь:

  • handleIn = (-50, 0)
  • handleOut = (50, 0)

Это формирует плавную кривую.


Работа с массивом сегментов

Путь хранит сегменты в массиве:

path.segments

Доступ к отдельному сегменту:

var segment = path.segments[0];

Изменение координаты точки:

segment.point.x += 50;

Изменение управляющих векторов:

segment.handleIn = new Point(-30, 0);
segment.handleOut = new Point(30, 0);

Добавление и удаление сегментов

Добавление:

path.add(new Point(300, 200));

Вставка в определённую позицию:

path.insert(1, new Point(150, 150));

Удаление:

path.removeSegment(0);

Очистка:

path.removeSegments();

Геометрия сегмента

Каждый сегмент содержит свойства, позволяющие точно управлять формой:

  • segment.point — объект Point
  • segment.handleIn
  • segment.handleOut

Проверка наличия кривизны:

if (!segment.handleIn.isZero() || !segment.handleOut.isZero()) {
    // сегмент участвует в кривой
}

Связь сегментов с кривыми

Каждая пара соседних сегментов образует кривую (Curve). Управляющие векторы определяют форму этой кривой.

Если:

  • оба вектора равны (0,0) — линия прямая
  • векторы заданы — линия становится кривой Безье

Пример:

var path = new Path();
path.add(new Segment(new Point(100, 100), null, new Point(50, 0)));
path.add(new Segment(new Point(200, 100), new Point(-50, 0), null));

Это создаёт плавную дугу между двумя точками.


Абсолютные и относительные координаты

Векторы handleIn и handleOut задаются относительно точки сегмента, а не в абсолютных координатах.

Пример:

segment.point = new Point(200, 200);
segment.handleOut = new Point(50, 0);

Фактическая управляющая точка будет:

(200 + 50, 200 + 0) = (250, 200)

Замкнутые пути и сегменты

Если путь замкнут:

path.closed = true;

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

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

  • фигур (круги, полигоны)
  • заливок

Итерация по сегментам

Обработка всех сегментов:

for (var i = 0; i < path.segments.length; i++) {
    var segment = path.segments[i];
    segment.point.x += 10;
}

Или современный вариант:

path.segments.forEach(function(segment) {
    segment.point.y += 20;
});

Сглаживание сегментов

Paper.js предоставляет метод сглаживания:

path.smooth();

Он автоматически настраивает handleIn и handleOut, создавая плавные переходы между сегментами.

Варианты сглаживания:

path.smooth({
    type: 'continuous'
});

Разделение сегмента

Добавление новой точки между существующими:

path.divideAt(0.5);

Аргумент — параметр кривой (от 0 до 1).

Это создаёт новый сегмент без изменения формы пути.


Преобразование сегментов

Перемещение:

segment.point += new Point(10, 0);

Масштабирование:

segment.point *= 1.2;

Вращение вокруг центра:

segment.point = segment.point.rotate(45, path.position);

Практика: построение кривой

var path = new Path();
path.strokeColor = 'black';

path.add(new Segment(new Point(100, 200), null, new Point(80, -80)));
path.add(new Segment(new Point(300, 200), new Point(-80, 80), null));

Результат — плавная S-образная кривая.


Динамическое изменение сегментов

Сегменты удобно использовать для анимации:

function onFrame(event) {
    path.segments.forEach(function(segment, index) {
        segment.point.y += Math.sin(event.time + index) * 0.5;
    });
}

Это создаёт эффект волны.


Копирование сегментов

var newSegment = segment.clone();

Используется для:

  • дублирования форм
  • построения производных путей

Особенности и ограничения

  • Сегменты не существуют отдельно от пути (обычно используются внутри Path)
  • Изменение сегмента автоматически обновляет путь
  • Управляющие векторы влияют только на соседние сегменты
  • Порядок сегментов критически важен

Визуальная отладка сегментов

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

path.selected = true;

Это включает визуализацию:

  • сегментов
  • управляющих линий

Итоговые принципы работы

  • Путь = последовательность сегментов
  • Сегмент = точка + управляющие векторы
  • Кривая = связь между сегментами
  • Управление формой осуществляется через handleIn и handleOut
  • Все изменения сегментов моментально отражаются на геометрии пути

Такой подход делает Paper.js мощным инструментом для точного и гибкого управления векторной графикой.