Валидация параметров

Любая геопространственная операция требует корректных входных данных. Ошибки в структуре GeoJSON, неверные координаты, отсутствие обязательных параметров или передача неподдерживаемых типов объектов способны привести к некорректным результатам вычислений либо к аварийному завершению программы.

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

Основные задачи валидации:

  • проверка типа геометрии;
  • контроль структуры GeoJSON;
  • проверка диапазонов координат;
  • контроль обязательных параметров;
  • проверка единиц измерения;
  • защита от пустых объектов;
  • предотвращение ошибок пространственных вычислений.

Типичные проблемы входных данных

На практике чаще всего встречаются следующие ошибки:

Неверный тип геометрии

Многие функции 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: {}
};

Попытка обработки такого объекта приведёт к исключению.


Повреждённая структура GeoJSON

Нередко данные поступают из внешних API и могут не соответствовать спецификации GeoJSON.

Пример:

const invalidPoint = {
    type: "Point",
    coordinates: [10, 20]
};

Формально это геометрия, но многие функции Turf.js ожидают объект Feature.

Корректный вариант:

const validPoint = turf.point([10, 20]);

Проверка типа объекта через geojsonType

Для контроля типа 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

Многие алгоритмы требуют не просто геометрию, а полноценный объект 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

Проверка коллекций через collectionOf

Если функция работает с 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 накладывает ограничения:

  • долгота: от -180 до 180;
  • широта: от -90 до 90.

Проверка:

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"
        );
    }
}

Проверка Polygon

Для полигона необходимо наличие минимум четырёх вершин, включая замыкающую.

Корректный пример:

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]
    );
}

Проверка MultiPolygon

Для сложных полигональных объектов требуется проверять все кольца.

Пример:

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);

Создание универсального валидатора Feature

На практике удобно объединять проверки.

Пример:

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…catch

Даже при тщательной валидации рекомендуется перехватывать исключения.

Пример:

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-файлов.