Subdivide и разделение кривых

В Paper.js метод subdivide() применяется для разбиения кривых Безье на более мелкие сегменты. Он используется, когда требуется повысить точность рендеринга кривой, добавить контрольные точки или подготовить кривую для анимации и деформации. Метод возвращает массив новых сегментов, которые образуют исходную кривую, сохраняя её форму.

let path = new Path();
path.add(new Point(50, 50));
path.add(new Point(150, 100));
path.add(new Point(250, 50));
path.strokeColor = 'black';

let subdivided = path.flatten(10); // альтернатива для упрощения кривой

В Paper.js есть два подхода к разбиению кривых: явное разбиение сегментов и разбиение по длине кривой.


Разделение кривой на сегменты

Метод Path#divideAt(offset) позволяет разделить путь в точке, заданной смещением вдоль кривой. Смещение измеряется в единицах длины кривой.

let path = new Path.Line({
    from: [0, 0],
    to: [200, 0],
    strokeColor: 'blue'
});

let firstPart = path.divideAt(100); // разделение кривой на две части

Результат деления — создание нового пути от точки разбиения до конца исходной кривой. Это удобно при анимации объектов вдоль кривой или при генерации отдельных сегментов для манипуляций.

Особенности метода divideAt:

  • Работает с любым типом Path: Line, Curve, CompoundPath.
  • Если точка деления совпадает с началом или концом пути, метод возвращает null.
  • Поддерживает дробные значения смещения, что позволяет точно контролировать разбиение кривой.

Использование flatten для разбиения кривых Безье

Метод flatten(tolerance) преобразует кривую в набор линейных сегментов с заданной точностью. Параметр tolerance определяет максимальное отклонение между исходной кривой и результатом разбиения.

let curve = new Path({
    segments: [[50, 200], [150, 100], [250, 200]],
    strokeColor: 'green'
});

curve.flatten(5); // кривая разбита на сегменты с точностью 5px

Ключевые моменты:

  • Чем меньше значение tolerance, тем больше сегментов будет создано.
  • Подходит для точного взаимодействия с кривыми при столкновениях, кликах или вычислении длины.
  • Flatten удобно использовать перед анимацией объектов вдоль кривой, чтобы избежать сложных вычислений кривых Безье.

Разделение кривой по процентам длины

Для более гибкого контроля разбиения можно использовать метод getLocationAt(offset) и divideAt(location):

let path = new Path.Arc({
    from: [50, 50],
    through: [150, 150],
    to: [250, 50],
    strokeColor: 'red'
});

let halfLength = path.length / 2;
let location = path.getLocationAt(halfLength);
let secondHalf = path.divideAt(location);

Этот подход позволяет:

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

Subdivide с помощью Path#segments

Для кривых, которые уже имеют контрольные точки, можно вручную создавать дополнительные сегменты через метод Path#insert(index, point). Сочетание с subdivide() позволяет создавать новые точки внутри кривой, сохраняя её форму.

let path = new Path({
    segments: [[50, 50], [150, 100], [250, 50]],
    strokeColor: 'purple'
});

let middle = path.getPointAt(path.length / 2);
path.insert(1, middle); // вставка точки в середину кривой

Преимущества такого подхода:

  • Точное управление расположением новых сегментов.
  • Возможность дальнейшей деформации кривой через изменение контрольных точек.
  • Полная совместимость с методами анимации и событиями мыши.

Использование Subdivide для анимации и визуальных эффектов

После разбиения кривой на сегменты становится возможным:

  • Анимация объектов вдоль кривой: каждый сегмент может быть использован как отдельный путь для движения объекта.
  • Создание динамических форм: сегменты можно смещать, деформировать, объединять в новые фигуры.
  • Эффекты линий и штриховки: разбиение кривой позволяет точно расставлять объекты вдоль пути, имитируя штриховку, точки или частицы.
let path = new Path.Arc({
    from: [100, 300],
    through: [200, 100],
    to: [300, 300],
    strokeColor: 'orange'
});

let segments = path.flatten(10); 
segments.forEach((point, i) => {
    let circle = new Path.Circle({
        center: point,
        radius: 3,
        fillColor: 'black'
    });
});

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


Итоги по методам Subdivide и разбиения кривых

  • divideAt(offset) — разделение кривой по длине для точного контроля сегментов.
  • flatten(tolerance) — преобразование кривой Безье в линейные сегменты для анимации и точных вычислений.
  • insert(index, point) и ручная вставка сегментов — точечное добавление контрольных точек для последующих изменений.
  • Использование getLocationAt(offset) позволяет разрабатывать сложные анимации и равномерно распределять объекты по кривой.

Эти методы в сочетании обеспечивают полный контроль над кривыми в Paper.js и позволяют создавать сложные графические эффекты с высокой точностью и гибкостью.