Subtract и вычитание

В Paper.js для работы с формами используется система Path и CompoundPath, которая позволяет выполнять булевы операции между объектами. Одной из ключевых операций является вычитание (subtract), которая позволяет вырезать одну форму из другой, создавая сложные композиции.

Метод subtract

Метод subtract применяется к объекту Path или CompoundPath и принимает в качестве аргумента другой объект Path, результатом чего становится новая фигура, представляющая область первой фигуры за вычетом второй.

let path1 = new Path.Circle({
    center: [150, 150],
    radius: 100,
    fillColor: 'blue'
});

let path2 = new Path.Circle({
    center: [200, 150],
    radius: 50,
    fillColor: 'red'
});

let result = path1.subtract(path2);
result.fillColor = 'green';

В примере выше из большого синего круга вырезается маленький красный, результат сохраняется в отдельной переменной result. Исходные объекты path1 и path2 остаются неизменными, что важно для дальнейшей работы.

Особенности работы с вычитанием

  1. Комбинация сложных фигур subtract корректно работает не только с простыми формами, но и с CompoundPath, состоящими из нескольких сегментов. Это позволяет создавать сложные контуры с «дырками» и вырезами.

  2. Сегменты и кривые В процессе вычитания Paper.js автоматически пересчитывает сегменты, соединяет кривые Безье и упрощает результирующий путь. Иногда это может привести к появлению мелких артефактов в виде лишних точек, особенно при пересечении сложных фигур.

  3. Сохранение оригиналов Для сохранения исходных объектов после операции необходимо явно клонировать их, иначе можно потерять исходные данные при дальнейшем изменении.

let path1Clone = path1.clone();
let result = path1Clone.subtract(path2);
  1. Направление контуров Paper.js учитывает направление кривых при вычислении вычитания. Контуры должны иметь правильное направление для корректного выреза — по часовой стрелке для внешнего контура и против часовой стрелки для дырок.

Комбинирование нескольких вычитаний

Можно последовательно вычитать несколько фигур из одной базовой формы:

let base = new Path.Rectangle([50, 50], [300, 200]);
let hole1 = new Path.Circle([100, 100], 40);
let hole2 = new Path.Circle([250, 150], 30);

let result = base.subtract(hole1).subtract(hole2);
result.fillColor = 'orange';

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

Интеграция с CompoundPath

Если необходимо вычесть не одну фигуру, а целую группу, удобно использовать CompoundPath:

let base = new Path.Rectangle([50, 50], [300, 200]);

let holes = new CompoundPath({
    children: [
        new Path.Circle([100, 100], 40),
        new Path.Circle([250, 150], 30)
    ]
});

let result = base.subtract(holes);
result.fillColor = 'purple';

CompoundPath позволяет объединить несколько фигур в один объект, после чего вычитание производится как одной операцией, что ускоряет обработку и упрощает структуру кода.

Важные советы по производительности

  • Минимизировать сложность фигур: вычитание сложных кривых с большим количеством сегментов может быть ресурсоемким. Для оптимизации рекомендуется уменьшать количество точек или использовать упрощенные контуры.
  • Использовать клоны для промежуточных результатов: это предотвращает потерю исходных данных и позволяет экспериментировать с формами.
  • Следить за пересечениями: при сложных пересечениях иногда возникают небольшие ошибки в контуре. В таких случаях помогает ручная корректировка сегментов.

Практические применения вычитания

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

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