Поиск в радиусе

Поиск объектов в радиусе в геопространственных задачах опирается на вычисление расстояний на поверхности Земли и проверку принадлежности точек заданной области. В Turf.js этот функционал реализуется через набор геометрических примитивов и пространственных операций, позволяющих строить запросы «вокруг точки» без использования серверных ГИС-систем.

Радиусный поиск в геоинформационных системах формализуется через множество точек, удовлетворяющих условию:

  • расстояние от центра до точки ≤ заданного радиуса

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

В Turf.js основой является работа с GeoJSON-объектами:

  • Point — координатная точка
  • Feature<Point> — точка с метаданными
  • Polygon и Circle — области поиска
  • FeatureCollection — набор объектов

Вычисление геодезического расстояния

Ключевой примитив для радиусного поиска — расстояние между двумя точками:

import distance from "@turf/distance";

const from = [76.8865, 43.2389];
const to = [76.9456, 43.2551];

const result = distance(from, to, { units: "kilometers" });

Функция учитывает кривизну Земли и возвращает расстояние в заданных единицах:

  • kilometers
  • meters
  • miles
  • degrees

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

Построение радиуса через круговую геометрию

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

import circle from "@turf/circle";

const center = [76.8865, 43.2389];
const radius = 5;

const options = {
  steps: 64,
  units: "kilometers"
};

const circlePolygon = circle(center, radius, options);

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

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

Проверка попадания точек в радиусную область

После построения области выполняется пространственная проверка:

import booleanPointInPolygon from "@turf/boolean-point-in-polygon";

const points = [
  [76.88, 43.23],
  [76.90, 43.25],
  [76.95, 43.27]
];

const within = points.filter((pt) =>
  booleanPointInPolygon(pt, circlePolygon)
);

Механизм основан на алгоритме ray casting, определяющем принадлежность точки полигону через пересечение луча с границами фигуры.

Альтернативный подход через буферизацию

Буферизация геометрии представляет более универсальный метод построения радиуса:

import buffer from "@turf/buffer";

const center = {
  type: "Feature",
  geometry: {
    type: "Point",
    coordinates: [76.8865, 43.2389]
  }
};

const buffered = buffer(center, 5, { units: "kilometers" });

Буфер создаёт полигон вокруг точки, эквидистантный на заданное расстояние. В отличие от circle, буфер может применяться к линиям и полигонам, расширяя сценарии использования.

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

import pointsWithinPolygon from "@turf/points-within-polygon";

const result = pointsWithinPolygon(featureCollectionOfPoints, buffered);

Прямой радиусный поиск через расстояние

Наиболее прямолинейный метод — фильтрация точек по расстоянию без построения полигонов:

import distance from "@turf/distance";

const center = [76.8865, 43.2389];

const filtered = points.filter((point) => {
  const d = distance(center, point, { units: "kilometers" });
  return d <= 5;
});

Данный подход используется при небольших объёмах данных или при предварительной фильтрации перед более сложной пространственной обработкой.

Оптимизация вычислений

При увеличении количества объектов линейный перебор становится вычислительно затратным. В практических системах применяется предварительная фильтрация по bounding box:

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

Пример подготовки ограничивающего прямоугольника:

import bbox from "@turf/bbox";

const box = bbox(circlePolygon);

Дальнейшая проверка выполняется перед точным вычислением расстояния.

Дополнительно используются пространственные индексы (например, R-tree через сторонние библиотеки), позволяющие уменьшить сложность поиска с O(n) до O(log n).

Особенности единиц измерения и точности

Все операции радиусного поиска зависят от параметра units. Несоответствие единиц приводит к систематическим ошибкам:

  • километры — стандарт для городских и региональных задач
  • метры — высокоточная локальная аналитика
  • мили — транспортные и навигационные системы

Геодезические вычисления в Turf.js используют сферическую модель, что создаёт погрешность, возрастающую с увеличением радиуса. Для малых расстояний (до 10–20 км) отклонения минимальны, но на глобальных масштабах требуется учитывать эллипсоидальные модели через внешние библиотеки.

Комбинированные сценарии радиусного поиска

В реальных задачах радиусный поиск редко используется изолированно. Типичная цепочка обработки включает:

  • фильтрацию по bounding box
  • вычисление расстояния через distance
  • уточнение через booleanPointInPolygon
  • агрегацию результатов в FeatureCollection

Пример комбинированного подхода:

import distance from "@turf/distance";
import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
import circle from "@turf/circle";

const center = [76.8865, 43.2389];

const searchArea = circle(center, 3, { units: "kilometers", steps: 64 });

const result = points.filter((p) => {
  if (!booleanPointInPolygon(p, searchArea)) return false;
  return distance(center, p, { units: "kilometers" }) <= 3;
});

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

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

Радиусные запросы в геоаналитике используются в задачах:

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

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

Геометрические ограничения модели

Радиусный поиск в Turf.js основан на предположении о гладкой поверхности Земли. Это приводит к следующим особенностям:

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

При работе вблизи полюсов и через 180-й меридиан требуется учитывать разрыв геометрии и корректно нормализовать координаты.

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

GeoJSON остаётся основной структурой передачи данных. При этом производительность зависит от:

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

Оптимизация достигается за счёт:

  • кэширования результатов circle и buffer
  • предварительного отбора по bbox
  • минимизации вызовов distance

При масштабировании до сотен тысяч точек радиусный поиск становится многоуровневой системой фильтров, где Turf.js выполняет роль геометрического ядра вычислений.