Любая геопространственная операция требует корректных входных данных. Ошибки в структуре GeoJSON, неверные координаты, отсутствие обязательных параметров или передача неподдерживаемых типов объектов способны привести к некорректным результатам вычислений либо к аварийному завершению программы.
В Turf.js валидация параметров представляет собой набор механизмов проверки входных данных перед выполнением геоаналитических операций. Проверки могут выполняться как встроенными средствами библиотеки, так и дополнительной пользовательской логикой.
Основные задачи валидации:
На практике чаще всего встречаются следующие ошибки:
Многие функции Turf.js работают только с определёнными типами объектов.
Например, функция вычисления длины маршрута ожидает LineString.
Некорректно:
const point = turf.point([30, 50]);
turf.length(point);
Результат:
Error: Input must be a LineString
Корректно:
const line = turf.lineString([
[30, 50],
[31, 51]
]);
turf.length(line);
Некоторые данные могут содержать пустую геометрию.
Пример ошибочного объекта:
const feature = {
type: "Feature",
geometry: null,
properties: {}
};
Попытка обработки такого объекта приведёт к исключению.
Нередко данные поступают из внешних API и могут не соответствовать спецификации GeoJSON.
Пример:
const invalidPoint = {
type: "Point",
coordinates: [10, 20]
};
Формально это геометрия, но многие функции Turf.js ожидают объект Feature.
Корректный вариант:
const validPoint = turf.point([10, 20]);
Для контроля типа GeoJSON используется вспомогательная функция
geojsonType.
Импорт:
import { geojsonType } from "@turf/invariant";
Пример проверки:
geojsonType(
turf.point([10, 20]),
"Point",
"myFunction"
);
Если объект имеет другой тип:
geojsonType(
turf.lineString([[0, 0], [1, 1]]),
"Point",
"myFunction"
);
Будет выброшено исключение:
Invalid input to myFunction: must be a Point
Такой подход полезен при разработке собственных функций поверх Turf.js.
Многие алгоритмы требуют не просто геометрию, а полноценный объект Feature.
Для этого применяется функция featureOf.
import { featureOf } from "@turf/invariant";
Проверка точки:
const point = turf.point([10, 20]);
featureOf(
point,
"Point",
"bufferOperation"
);
Ошибка при передаче линии:
const line = turf.lineString([
[0, 0],
[1, 1]
]);
featureOf(
line,
"Point",
"bufferOperation"
);
Результат:
Invalid input to bufferOperation
Если функция работает с FeatureCollection, полезно контролировать состав коллекции.
Импорт:
import { collectionOf } from "@turf/invariant";
Пример:
const points = turf.featureCollection([
turf.point([10, 10]),
turf.point([20, 20])
]);
collectionOf(
points,
"Point",
"clusterAnalysis"
);
Если в коллекции окажется другой тип:
const mixedCollection = turf.featureCollection([
turf.point([10, 10]),
turf.lineString([[0, 0], [1, 1]])
]);
collectionOf(
mixedCollection,
"Point",
"clusterAnalysis"
);
Возникнет исключение.
Подобная проверка особенно полезна перед пространственной кластеризацией и статистическим анализом.
Перед вычислениями часто требуется убедиться, что координаты существуют.
Простейшая проверка:
function hasCoordinates(feature) {
return (
feature &&
feature.geometry &&
feature.geometry.coordinates
);
}
Использование:
if (!hasCoordinates(feature)) {
throw new Error("Coordinates not found");
}
Система WGS84 накладывает ограничения:
Проверка:
function validateCoordinate([lng, lat]) {
return (
lng >= -180 &&
lng <= 180 &&
lat >= -90 &&
lat <= 90
);
}
Пример:
validateCoordinate([30, 50]);
Вернёт:
true
Некорректный пример:
validateCoordinate([250, 100]);
Вернёт:
false
Для линий и полигонов необходимо контролировать каждую вершину.
Пример:
function validateCoordinates(coords) {
return coords.every(
([lng, lat]) =>
lng >= -180 &&
lng <= 180 &&
lat >= -90 &&
lat <= 90
);
}
Использование:
const line = [
[30, 50],
[31, 51],
[32, 52]
];
validateCoordinates(line);
Функция buffer() требует корректного радиуса.
Неверный пример:
turf.buffer(point, -10);
Отрицательный радиус не имеет практического смысла.
Предварительная проверка:
function validateRadius(radius) {
if (typeof radius !== "number") {
throw new Error("Radius must be number");
}
if (radius <= 0) {
throw new Error("Radius must be positive");
}
}
Использование:
validateRadius(radius);
const result = turf.buffer(point, radius);
Многие функции Turf.js используют параметр units.
Допустимые значения:
meters
kilometers
miles
degrees
radians
feet
yards
Проверка:
const allowedUnits = [
"meters",
"kilometers",
"miles",
"degrees",
"radians",
"feet",
"yards"
];
function validateUnits(units) {
if (!allowedUnits.includes(units)) {
throw new Error(
`Unsupported unit: ${units}`
);
}
}
Использование:
validateUnits("kilometers");
Геопространственные вычисления часто используют числовые аргументы.
Например:
turf.along(line, distance);
Проверка:
function validateDistance(distance) {
if (
typeof distance !== "number" ||
Number.isNaN(distance)
) {
throw new Error(
"Distance must be a valid number"
);
}
if (distance < 0) {
throw new Error(
"Distance cannot be negative"
);
}
}
Для полигона необходимо наличие минимум четырёх вершин, включая замыкающую.
Корректный пример:
const polygon = turf.polygon([
[
[0, 0],
[10, 0],
[10, 10],
[0, 0]
]
]);
Проверка:
function validatePolygon(coords) {
return coords[0].length >= 4;
}
Более строгий вариант:
function validatePolygon(coords) {
const ring = coords[0];
if (ring.length < 4) {
return false;
}
const first = ring[0];
const last = ring[ring.length - 1];
return (
first[0] === last[0] &&
first[1] === last[1]
);
}
Для сложных полигональных объектов требуется проверять все кольца.
Пример:
function validateMultiPolygon(multiPolygon) {
return multiPolygon.every(
polygon =>
polygon.every(
ring => ring.length >= 4
)
);
}
Подобная проверка помогает избежать ошибок в функциях:
turf.area(...)
turf.intersect(...)
turf.union(...)
Перед запуском пространственного анализа желательно убедиться, что коллекция содержит элементы.
Проверка:
function validateCollection(collection) {
if (
!collection.features ||
collection.features.length === 0
) {
throw new Error(
"FeatureCollection is empty"
);
}
}
Использование:
validateCollection(fc);
На практике удобно объединять проверки.
Пример:
function validateFeature(feature) {
if (!feature) {
throw new Error(
"Feature is required"
);
}
if (feature.type !== "Feature") {
throw new Error(
"Invalid Feature type"
);
}
if (!feature.geometry) {
throw new Error(
"Geometry is missing"
);
}
if (!feature.geometry.coordinates) {
throw new Error(
"Coordinates are missing"
);
}
return true;
}
Использование:
validateFeature(feature);
const area = turf.area(feature);
Предположим, разрабатывается функция вычисления площади участка.
Без проверки:
function calculateArea(feature) {
return turf.area(feature);
}
Безопасный вариант:
function calculateArea(feature) {
featureOf(
feature,
"Polygon",
"calculateArea"
);
return turf.area(feature);
}
Теперь ошибка будет обнаружена до начала вычислений.
Даже при тщательной валидации рекомендуется перехватывать исключения.
Пример:
try {
const result =
turf.buffer(point, radius);
console.log(result);
}
catch (error) {
console.error(
"Buffer creation failed:",
error.message
);
}
Подход позволяет предотвратить аварийное завершение приложения.
В крупных проектах удобно выносить проверки в отдельный модуль.
Структура:
validators/
├── coordinates.js
├── geometry.js
├── polygon.js
├── units.js
└── feature.js
Пример агрегирующего файла:
export {
validateCoordinate
} from "./coordinates.js";
export {
validateUnits
} from "./units.js";
export {
validateFeature
} from "./feature.js";
Использование:
import {
validateFeature,
validateUnits
} from "./validators";
Такой подход обеспечивает:
Проверка данных должна выполняться до вызова функций Turf.js, а не после получения ошибки.
Тип геометрии необходимо контролировать явно, особенно при работе с внешними источниками данных.
Координаты следует проверять на допустимые диапазоны, даже если данные поступают из доверенной системы.
Числовые параметры должны проходить контроль на тип, диапазон и наличие значения.
FeatureCollection требует проверки на пустоту и однородность состава.
Встроенные функции пакета @turf/invariant
желательно использовать в пользовательских алгоритмах как первый уровень
защиты от некорректных данных.
Все потенциально опасные операции рекомендуется оборачивать в
try...catch, особенно при обработке пользовательского ввода
и внешних GeoJSON-файлов.