getPointAt и получение точек на кривой

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


Синтаксис и параметры

var point = path.getPointAt(offset);
  • offset — расстояние вдоль кривой от её начала, выраженное в пикселях.
  • Возвращаемое значение — объект Point, представляющий координаты точки на кривой в системе координат Paper.js.
  • Если offset превышает длину кривой, возвращается null.

Принцип работы

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

Пример вычисления длины и получения точек:

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

var totalLength = path.length;
console.log('Длина кривой:', totalLength);

var pointAtQuarter = path.getPointAt(totalLength / 4);
console.log('Точка на 1/4 длины кривой:', pointAtQuarter);

Здесь totalLength вычисляет общую длину кривой, а getPointAt возвращает точку, находящуюся на 25% от начала пути.


Использование getPointAt для анимации

Одна из частых задач — перемещение объекта вдоль кривой с постоянной скоростью. Прямое использование параметра t (getPointAt(t)) не даёт равномерного движения по длине, так как кривые Bezier имеют нелинейное распределение по параметру. Использование offset решает эту проблему.

var circle = new Path.Circle({
    center: [0, 0],
    radius: 5,
    fillColor: 'red'
});

var offset = 0;
function onFrame(event) {
    offset += 2; // скорость движения
    if (offset > path.length) offset = 0;
    circle.position = path.getPointAt(offset);
}
  • Постоянное увеличение offset обеспечивает равномерное движение вдоль кривой.
  • Обнуление offset позволяет зациклить движение.

Получение нескольких точек с равными интервалами

Для визуализации или анализа кривой часто требуется получить набор точек с равным шагом. Шаг определяется через длину кривой и количество точек:

var pointsCount = 10;
var step = path.length / (pointsCount - 1);
var points = [];

for (var i = 0; i < pointsCount; i++) {
    points.push(path.getPointAt(i * step));
}

// Отображение точек
points.forEach(function(p) {
    new Path.Circle({
        center: p,
        radius: 3,
        fillColor: 'blue'
    });
});
  • Это позволяет равномерно распределить точки по кривой, независимо от её геометрии.
  • Даже на кривых с резкими изгибами точки будут распределены по длине, а не по параметру t.

Связь с getTangentAt и getNormalAt

Метод getPointAt часто используется вместе с:

  • getTangentAt(offset) — возвращает направление касательной в точке на кривой.
  • getNormalAt(offset) — возвращает нормаль к кривой в точке.

Пример комбинированного использования:

var point = path.getPointAt(100);
var tangent = path.getTangentAt(100);
var normal = path.getNormalAt(100);

console.log('Точка:', point);
console.log('Касательная:', tangent);
console.log('Нормаль:', normal);
  • Позволяет строить объекты, ориентированные вдоль кривой (стрелки, текст, элементы интерфейса).
  • Касательная всегда единичной длины, нормаль перпендикулярна касательной.

Особенности для сложных кривых

  • Для составных Path (состоящих из нескольких сегментов) getPointAt автоматически учитывает все сегменты.
  • Если нужно получить точку отдельного сегмента, используется getPointAt(offset) на соответствующем сегменте.
  • Методы getPointAt, getTangentAt и getNormalAt используют внутреннюю аппроксимацию длины кривой, что позволяет работать даже с кривыми высокой сложности без ручного расчета.

Практические советы

  1. Для анимации с постоянной скоростью всегда использовать offset, а не параметр t.
  2. Для равномерного распределения точек делить длину кривой на необходимое количество сегментов.
  3. Для визуализации касательных и нормалей удобно строить линии с помощью getTangentAt и getNormalAt с масштабированием.
var scale = 20; // длина визуализации
var offset = 50;
var tangent = path.getTangentAt(offset);
var normal = path.getNormalAt(offset);

new Path.Line({
    from: path.getPointAt(offset),
    to: path.getPointAt(offset).add(tangent.multiply(scale)),
    strokeColor: 'green'
});

new Path.Line({
    from: path.getPointAt(offset),
    to: path.getPointAt(offset).add(normal.multiply(scale)),
    strokeColor: 'orange'
});

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


Сводка ключевых моментов

  • getPointAt(offset) возвращает точку по длине кривой, а не по параметру t.
  • Работает на сложных кривых и Path с несколькими сегментами.
  • Используется для анимации, анализа кривой, построения равномерных сеток точек.
  • В сочетании с getTangentAt и getNormalAt позволяет строить ориентированные объекты и визуализировать направление кривой.
  • Равномерное распределение точек обеспечивается делением общей длины кривой на шаг, а не на количество сегментов.

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