Удаление дубликатов точек

Дублирующиеся координаты в наборах геометрии возникают на разных этапах обработки пространственных данных: при конвертации форматов, при объединении слоёв, при импорте из GPS-треков, при агрегации пользовательских событий или при многократном выполнении геоопераций. В контексте Turf.js такие дубликаты влияют на корректность вычислений длины, площади, направлений и топологических операций.

Дубликаты можно условно разделить на два типа:

1. Последовательные дубликаты Когда одинаковые координаты идут подряд внутри LineString или Polygon:

[10, 10] → [10, 10] → [11, 11]

2. Глобальные дубликаты Когда одинаковые точки встречаются в разных частях геометрии:

[10, 10] ... [50, 50] ... [10, 10]

Разница между этими случаями критична: первый тип устраняется локальной очисткой координат, второй требует полноценной дедупликации набора.


Базовые структуры Turf.js для работы с точками

Turf.js оперирует GeoJSON-объектами и предоставляет минимальный набор инструментов для итерации и трансформации координат.

Ключевые функции:

  • turf.point — создание точки
  • turf.featureCollection — объединение геометрий
  • turf.coordEach — итерация по всем координатам
  • turf.cleanCoords — удаление последовательных дублей
  • turf.booleanEqual — сравнение геометрий на равенство

Фундаментальная особенность Turf.js: библиотека не хранит состояние данных, а работает исключительно через трансформацию GeoJSON.


Удаление последовательных дубликатов координат

Наиболее частая проблема — повторяющиеся соседние точки в LineString и Polygon. Turf.js решает её встроенной функцией:

import { cleanCoords } from "@turf/turf";

const line = {
  type: "Feature",
  geometry: {
    type: "LineString",
    coordinates: [
      [30, 10],
      [30, 10],
      [31, 11],
      [31, 11],
      [32, 12]
    ]
  }
};

const cleaned = cleanCoords(line);

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

cleanCoords проходит по массиву координат и удаляет только те точки, которые:

  • совпадают с предыдущей
  • не влияют на форму линии или полигона

Важно: функция не удаляет глобальные дубликаты, а работает только локально.


Поведение cleanCoords в разных типах геометрии

LineString

Для линий удаляются повторяющиеся соседние координаты, при этом структура сохраняется.

Polygon

Для полигонов дополнительно учитывается замыкание контура. Если последняя точка совпадает с первой, лишнее повторение устраняется, но замкнутость сохраняется.

MultiGeometry

Вложенные геометрии обрабатываются рекурсивно, каждая компонента очищается отдельно.


Глобальная дедупликация набора точек

Когда требуется удалить все повторяющиеся точки в пределах FeatureCollection, используется другой подход.

Итерация через coordEach

import { coordEach } from "@turf/turf";

const seen = new Set();
const result = [];

coordEach(featureCollection, (coord) => {
  const key = coord.join(",");
  if (!seen.has(key)) {
    seen.add(key);
    result.push(coord);
  }
});

Ключевой принцип

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


Восстановление структуры после дедупликации

Удаление координат в “плоском” виде разрушает геометрию, поэтому результат необходимо собирать обратно:

import { point, featureCollection } from "@turf/turf";

const features = result.map(c => point(c));

const fc = featureCollection(features);

Однако такой подход применим только для точечных наборов. Для LineString и Polygon требуется восстановление последовательностей, иначе геометрия теряет смысл.


Дедупликация с учетом геометрической эквивалентности

Иногда недостаточно сравнения координат — важно учитывать идентичность объектов.

Turf.js предоставляет:

import { booleanEqual } from "@turf/turf";

Использование booleanEqual

if (booleanEqual(featureA, featureB)) {
  // геометрии идентичны
}

Этот метод проверяет полное геометрическое совпадение, включая порядок координат и тип геометрии.


Удаление дубликатов сложных структур

При работе с FeatureCollection часто встречается ситуация, когда:

  • одинаковые точки находятся в разных LineString
  • пересекающиеся полигоны содержат идентичные вершины
  • GPS-треки дублируются при агрегации данных

Подход через нормализацию координат

Один из устойчивых методов — нормализация координат перед сравнением:

const normalize = (coord) => `${coord[0].toFixed(6)}:${coord[1].toFixed(6)}`;

Далее используется Set:

const set = new Set();

coordEach(fc, (coord) => {
  set.add(normalize(coord));
});

Такой подход устраняет ошибки, связанные с плавающей точкой.


Работа с полигонами и сохранением топологии

Удаление дубликатов в полигонах требует аккуратности:

  • нельзя нарушать замкнутость кольца
  • нельзя удалять вершины, влияющие на форму
  • нельзя допускать вырождения (менее 3 уникальных точек)

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

  • достаточное количество координат
  • сохранение ориентации кольца
  • отсутствие самопересечений (если требуется строгая геометрия)

Комбинирование cleanCoords и ручной дедупликации

Практическая схема обработки часто состоит из двух этапов:

  1. Локальная очистка:
const step1 = cleanCoords(feature);
  1. Глобальная фильтрация:
coordEach(step1, (coord) => {
  // удаление глобальных дублей
});

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


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

При работе с десятками тысяч точек ключевым фактором становится производительность.

Использование Map вместо Set

Map позволяет хранить дополнительные метаданные:

const map = new Map();

coordEach(fc, (coord) => {
  const key = coord[0] + ":" + coord[1];
  if (!map.has(key)) {
    map.set(key, true);
  }
});

Минимизация сериализации

Избегание JSON.stringify ускоряет обработку, особенно при потоковой обработке координат.


Типичные ошибки при удалении дубликатов

1. Потеря структуры LineString Удаление координат без восстановления последовательности приводит к разрывам линии.

2. Нарушение замыкания Polygon Удаление первой или последней точки может разомкнуть контур.

3. Игнорирование точности float Координаты [10.0000001, 20] и [10, 20] могут считаться разными без нормализации.

4. Избыточная дедупликация Удаление всех повторов без учета топологии приводит к деградации геометрии.


Практические паттерны обработки данных

Очистка GPS-трека

  • удаление подряд идущих дублей через cleanCoords
  • сглаживание шумов
  • последующая фильтрация глобальных повторов

Подготовка данных для кластеризации

  • нормализация координат
  • удаление идентичных точек
  • преобразование в FeatureCollection точек

Предобработка перед анализом расстояний

  • устранение повторов
  • контроль плотности точек
  • исключение нулевых сегментов

Сравнение стратегий удаления дубликатов

cleanCoords

  • быстрое выполнение
  • работает локально
  • сохраняет структуру
  • не удаляет глобальные повторы

coordEach + Set

  • полная дедупликация
  • требует ручного восстановления структуры
  • гибкость обработки

booleanEqual

  • сравнение целых геометрий
  • не используется для точечных массивов
  • полезен при фильтрации FeatureCollection

Обработка больших FeatureCollection

При масштабировании важно учитывать:

  • потоковую обработку координат
  • минимизацию промежуточных массивов
  • отказ от глубокой копии объектов
  • использование итераторов вместо преобразований

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