Упрощение путей

Two.js предоставляет удобные инструменты для работы с векторной графикой, в том числе создание и редактирование пути (Path). Пути состоят из последовательности вершин (Vector) и могут быть как замкнутыми, так и открытыми. Оптимизация и упрощение путей позволяет уменьшить количество точек без потери визуальной формы, что важно для производительности и плавности анимаций.


Основные компоненты пути

Path в Two.js формируется с помощью объекта Two.Path. Ключевые свойства:

  • vertices – массив объектов Two.Vector, задающий точки пути.
  • closed – логическое значение, определяющее замкнутый ли путь.
  • curved – определяет, будут ли линии между точками кривыми или прямыми.
  • stroke и fill – цвет обводки и заливки.
  • linewidth – толщина линии.

Пример создания простого пути:

const path = two.makePath(
  new Two.Anchor(0, 0),
  new Two.Anchor(50, 0),
  new Two.Anchor(50, 50),
  new Two.Anchor(0, 50),
  true
);
path.stroke = '#000000';
path.fill = '#ff0000';
path.linewidth = 2;

Методы упрощения пути

1. Удаление лишних точек

Массив vertices можно фильтровать по критерию близости соседних точек. Например:

function simplifyVertices(vertices, tolerance) {
  const simplified = [vertices[0]];
  
  for (let i = 1; i < vertices.length; i++) {
    const last = simplified[simplified.length - 1];
    const current = vertices[i];
    const dx = current.x - last.x;
    const dy = current.y - last.y;
    if (Math.sqrt(dx*dx + dy*dy) > tolerance) {
      simplified.push(current);
    }
  }
  
  return simplified;
}

path.vertices = simplifyVertices(path.vertices, 5);

Пояснение: этот метод оставляет только точки, расстояние между которыми больше заданного порога tolerance, убирая мелкие колебания и перегруженные сегменты.


2. Алгоритм Рамер–Дугласа–Пекера (Ramer–Douglas–Peucker)

Этот алгоритм используется для более точного упрощения кривых, сохраняя их форму:

function rdp(points, epsilon) {
  let dmax = 0;
  let index = 0;
  const end = points.length - 1;

  for (let i = 1; i < end; i++) {
    const d = perpendicularDistance(points[i], points[0], points[end]);
    if (d > dmax) {
      index = i;
      dmax = d;
    }
  }

  if (dmax > epsilon) {
    const recResults1 = rdp(points.slice(0, index+1), epsilon);
    const recResults2 = rdp(points.slice(index), epsilon);
    return recResults1.slice(0, -1).concat(recResults2);
  } else {
    return [points[0], points[end]];
  }
}

function perpendicularDistance(point, lineStart, lineEnd) {
  const dx = lineEnd.x - lineStart.x;
  const dy = lineEnd.y - lineStart.y;
  return Math.abs(dy*point.x - dx*point.y + lineEnd.x*lineStart.y - lineEnd.y*lineStart.x) /
         Math.sqrt(dx*dx + dy*dy);
}

path.vertices = rdp(path.vertices, 2);

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

  • Позволяет уменьшить количество точек до минимально необходимого числа.
  • Сохраняет общую форму кривой.
  • Можно настраивать epsilon для контроля точности.

3. Сглаживание кривых

После упрощения пути можно дополнительно сгладить линии:

path.curved = true;
path.cap = 'round';
path.join = 'round';

Использование свойства curved позволяет Two.js автоматически интерполировать кривые между точками, делая визуализацию плавной.


Оптимизация производительности

При работе с большим количеством вершин и сложными анимациями:

  • Минимизировать количество вершин перед добавлением пути на сцену.
  • Применять упрощение только к изменяющимся сегментам пути.
  • Использовать Two.Path.makeObservable() для автоматического обновления сцены после изменения вершин.

Пример:

Two.Path.makeObservable(path);
path.vertices = rdp(path.vertices, 1.5);
two.update();

Важные моменты

  • Упрощение пути не всегда требуется, если путь статический и имеет мало точек.
  • Алгоритмы типа RDP лучше применять для сложных кривых и ломаных линий.
  • Параметр точности (epsilon) критичен: слишком большое значение может сильно исказить форму, слишком маленькое — не даст заметного эффекта.

Практическое применение

  1. Анимация рисования линий: упрощение позволяет плавнее анимировать длинные линии.
  2. SVG импорт: сложные SVG-пути часто содержат тысячи точек, их упрощение улучшает производительность.
  3. Интерактивные графики: уменьшение количества вершин снижает нагрузку на рендеринг при обновлениях в реальном времени.

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