getNormalAt и нормали

В библиотеке Paper.js нормаль является вектором, перпендикулярным касательной к кривой в определённой точке. Метод getNormalAt позволяет получить единичный вектор нормали в заданной позиции на пути (Path), что особенно важно при работе с кривыми, эффектами освещения, столкновениями и динамическими анимациями.


Основной синтаксис

path.getNormalAt(offset);
  • path — объект Path или CompoundPath.
  • offset — расстояние вдоль кривой от её начала. Измеряется в пикселях.
  • Возвращает объект Point, представляющий нормаль (единичный вектор) в этой точке.

Пример:

var path = new Path.Circle({
    center: [100, 100],
    radius: 50,
    strokeColor: 'black'
});

var normal = path.getNormalAt(0);
console.log(normal); // Point с координатами нормали

Здесь getNormalAt(0) возвращает нормаль в начале окружности. Если путь замкнут, offset можно использовать циклически: значение, превышающее длину пути, будет учитываться по модулю длины.


Нормали на кривых Безье

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

var path = new Path();
path.add(new Point(50, 200));
path.add(new Point(150, 50));
path.add(new Point(250, 200));
path.smooth();

var normal = path.getNormalAt(75); // нормаль на 75 пикселей от начала пути
console.log(normal.length); // всегда 1, нормаль нормализована

Важно понимать, что нормаль всегда нормализована (длина = 1), что удобно для операций смещения объектов вдоль кривой или направления эффекта.


Использование нормали для смещения

Нормаль часто используется для создания смещённых копий кривой, эффектов “обводки” и динамических анимаций. Пример:

var path = new Path.Line([50, 50], [200, 200]);
path.strokeColor = 'black';

var offset = 20;
for (var i = 0; i < path.length; i += 10) {
    var point = path.getPointAt(i);
    var normal = path.getNormalAt(i);
    var shiftedPoint = point.add(normal.multiply(offset));

    new Path.Circle({
        center: shiftedPoint,
        radius: 3,
        fillColor: 'red'
    });
}

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


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

Для замкнутых путей (например, Path.Circle или Path.Rectangle) направление нормали всегда наружу от фигуры, что соответствует стандартному математическому определению.

var circle = new Path.Circle([100, 100], 50);
circle.strokeColor = 'blue';

var normal = circle.getNormalAt(0);
console.log(normal); // [1, 0] — направлена наружу по X

Если требуется нормаль внутрь фигуры, можно просто умножить её на -1:

var inwardNormal = normal.multiply(-1);

Взаимодействие с касательными

Метод getNormalAt тесно связан с getTangentAt, который возвращает касательный вектор в точке. Связь между касательной и нормалью выражается через вращение на 90°:

var tangent = path.getTangentAt(50);
var normal = tangent.rotate(90).normalize();

В большинстве случаев использовать getNormalAt проще, так как Paper.js уже возвращает нормаль, и вручную вычислять вращение касательной не требуется.


Частые ошибки при использовании

  1. Неправильный offset: если offset превышает длину пути, для незамкнутого пути вернётся null.
  2. Пустой путь: метод не работает на пустых Path.
  3. Сложные CompoundPath: для CompoundPath offset считается по всему составу, что иногда вызывает неожиданные результаты. Лучше работать с отдельными Path.

Примеры применения

  • Создание эффектов тени и свечения вдоль кривой.
  • Построение динамических контуров для объектов в анимации.
  • Размещение объектов вдоль кривой с учётом нормали для 3D-подобного смещения.
  • Векторная визуализация направления кривой в геометрических и математических приложениях.

Оптимизация при больших путях

Для длинных или сложных кривых частое использование getNormalAt может быть ресурсоёмким. Рекомендуется:

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

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