Matrix и низкоуровневые преобразования

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

Создание и инициализация матриц

Объект матрицы создается с помощью конструктора:

let m = new paper.Matrix();

По умолчанию матрица инициализируется как единичная (identity matrix), что означает отсутствие преобразования. Для установки значений вручную используется конструктор с параметрами:

let m = new paper.Matrix(a, b, c, d, tx, ty);

где:

  • a, d — масштаб по осям X и Y,
  • b, c — сдвиг для наклона (shear),
  • tx, ty — смещение по X и Y (translation).

Основные операции матрицы

Смещение (Translation)

Смещение изменяет положение объекта на холсте без изменения его формы:

m.translate(new paper.Point(50, 100));

Смещение можно применить к объекту через его матрицу трансформации:

path.matrix = m;

Масштабирование (Scaling)

Масштабирование увеличивает или уменьшает размеры объекта относительно заданной точки:

m.scale(2); // Масштабирование в 2 раза относительно центра
m.scale(1.5, 0.5, new paper.Point(100, 100)); // Масштабирование с разными коэффициентами по X и Y

Ключевой момент: если не указана точка, масштабирование выполняется относительно начала координат (0,0), что может привести к смещению объекта.

Вращение (Rotation)

Вращение осуществляется вокруг центра или заданной точки:

m.rotate(45); // Вращение на 45 градусов
m.rotate(30, new paper.Point(200, 200)); // Вращение вокруг точки (200,200)

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

Наклон (Shearing)

Наклон или сдвиг по осям задается через параметры b и c:

m.skew(20, 10); // 20° по X, 10° по Y

Наклон позволяет создавать перспективные эффекты и трансформации, недоступные стандартными методами.

Комбинирование матриц

Матрицы можно комбинировать через умножение. Порядок операций имеет решающее значение, так как матричное умножение не коммутативно:

let m1 = new paper.Matrix();
m1.translate(100, 0);

let m2 = new paper.Matrix();
m2.rotate(45);

let combined = m1.appended(m2);

Метод appended() возвращает новую матрицу, комбинируя преобразования: сначала выполняется m1, затем m2. Для изменения исходной матрицы используется метод append().

m1.append(m2); // m1 теперь включает оба преобразования

Применение матрицы к объектам

Каждый объект в Paper.js имеет свойство matrix, которое можно модифицировать напрямую:

let path = new paper.Path.Rectangle([50, 50], [100, 100]);
path.matrix.rotate(30);
path.matrix.translate([20, 50]);

Также можно использовать метод transform() для применения произвольной матрицы:

let m = new paper.Matrix();
m.scale(2);
path.transform(m);

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

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

Иногда необходимо вернуть объект к исходному состоянию. Для этого используется инвертированная матрица:

let inv = m.inverted();
path.transform(inv);

Метод invert() изменяет текущую матрицу на её обратную:

m.invert();

Комбинированные трансформации и порядок

Важно помнить, что последовательность операций влияет на результат. Например:

let m = new paper.Matrix();
m.translate(50, 50);
m.rotate(45);

Или наоборот:

let m = new paper.Matrix();
m.rotate(45);
m.translate(50, 50);

Результаты будут различаться, так как вращение и смещение относительно разных центров создают разные положения объекта.

Работа с точками через матрицы

Матрицы позволяют преобразовывать отдельные точки:

let point = new paper.Point(100, 100);
let newPoint = m.transform(point);

Это полезно для вычислений геометрии, коллизий и анимаций, когда нужно знать точное положение точек после трансформаций.

Итоговые рекомендации по низкоуровневым матрицам

  • Использовать матрицы для сложных или комбинированных трансформаций, где стандартные методы rotate(), scale() и translate() могут быть недостаточны.
  • Всегда учитывать порядок операций.
  • Для анимации объектов лучше применять transform() с заранее подготовленными матрицами.
  • Для возврата к исходной форме объекта применять инвертированные матрицы.

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