В OpenLayers геометрия рассматривается как структурированный объект, описывающий пространственные данные: точки, линии, полигоны и их комбинации. Корректность таких объектов критична для рендеринга, пространственных операций и обмена данными через GeoJSON/WKT.
Валидность геометрии определяется соответствием геометрического объекта набору правил, зависящих от типа:
OpenLayers не навязывает строгую топологическую проверку по
умолчанию, оставляя это прикладной логике, но предоставляет инструменты
для работы с геометриями через ol/geom и форматами
сериализации.
Основные классы геометрий OpenLayers:
PointLineStringLinearRingPolygonMultiPointMultiLineStringMultiPolygonGeometryCollectionОшибки валидности чаще всего возникают на уровнях:
Координаты должны быть числами в формате [x, y] или
[x, y, z].
Проблемные случаи:
null или undefined;LineString требует минимум двух точек.
LinearRing требует минимум четырёх координат, причём первая
и последняя должны совпадать.
Polygon состоит из массива колец:
Типичные нарушения:
OpenLayers предоставляет доступ к координатам через методы
getCoordinates() и setCoordinates(), что
позволяет выполнять первичную валидацию на уровне структуры.
Простейшая проверка может быть реализована вручную:
import Polygon from 'ol/geom/Polygon';
function isFiniteNumber(value) {
return typeof value === 'number' && isFinite(value);
}
function validateCoordinate(coord) {
if (!Array.isArray(coord)) return false;
if (!isFiniteNumber(coord[0]) || !isFiniteNumber(coord[1])) return false;
return true;
}
function validateLinearRing(ring) {
if (!Array.isArray(ring) || ring.length < 4) return false;
const first = ring[0];
const last = ring[ring.length - 1];
if (first[0] !== last[0] || first[1] !== last[1]) return false;
return ring.every(validateCoordinate);
}
function validatePolygon(polygon) {
const coords = polygon.getCoordinates();
if (!Array.isArray(coords) || coords.length === 0) return false;
const outerRing = coords[0];
if (!validateLinearRing(outerRing)) return false;
return true;
}
Такой уровень проверки покрывает синтаксическую корректность, но не геометрическую топологию.
Самопересечение — одна из наиболее частых причин невалидных полигонов. OpenLayers не содержит встроенного детектора самопересечений, поэтому используются алгоритмы сторонних библиотек или ручная реализация.
Каждый сегмент линии проверяется на пересечение с другими сегментами, исключая соседние.
Алгоритм:
Упрощённая проверка пересечения:
function orientation(a, b, c) {
return (b[1] - a[1]) * (c[0] - b[0]) -
(b[0] - a[0]) * (c[1] - b[1]);
}
function segmentsIntersect(a, b, c, d) {
const o1 = orientation(a, b, c);
const o2 = orientation(a, b, d);
const o3 = orientation(c, d, a);
const o4 = orientation(c, d, b);
return (o1 * o2 < 0) && (o3 * o4 < 0);
}
Для полигона:
function hasSelfIntersection(ring) {
for (let i = 0; i < ring.length - 1; i++) {
for (let j = i + 1; j < ring.length - 1; j++) {
if (Math.abs(i - j) <= 1) continue;
if (i === 0 && j === ring.length - 2) continue;
if (segmentsIntersect(
ring[i], ring[i + 1],
ring[j], ring[j + 1]
)) {
return true;
}
}
}
return false;
}
Для серьёзной геопространственной валидации применяются специализированные библиотеки:
JSTS (JavaScript Topology Suite)Turf.jsGEOS через серверные решенияimport GeoJSON from 'ol/format/GeoJSON';
import { GeometryFactory } from 'jsts/org/locationtech/jts/geom';
function validateWithJSTS(feature) {
const format = new GeoJSON();
const geojson = format.writeFeatureObject(feature);
const reader = new jsts.io.GeoJSONReader();
const geom = reader.read(geojson.geometry);
return geom.isValid();
}
Метод isValid() проверяет:
При загрузке данных через ol/format/GeoJSON возможны
ошибки входного формата.
import GeoJSON from 'ol/format/GeoJSON';
const format = new GeoJSON();
const features = format.readFeatures(geojsonData, {
featureProjection: 'EPSG:3857'
});
Проблемные случаи:
type: "Feature" или
FeatureCollection;null;Дополнительная проверка структуры:
function validateGeoJSONGeometry(geometry) {
if (!geometry || !geometry.type) return false;
if (geometry.type === 'Polygon') {
return Array.isArray(geometry.coordinates);
}
if (geometry.type === 'LineString') {
return Array.isArray(geometry.coordinates);
}
return true;
}
OpenLayers оперирует координатами в разных проекциях, чаще всего:
EPSG:4326 (географические координаты);EPSG:3857 (Web Mercator).Несоответствие проекций приводит к визуально некорректной геометрии и ошибкам пространственного анализа.
Типичный сценарий ошибки:
EPSG:4326;EPSG:3857 без трансформации.Корректная трансформация:
import { transform } from 'ol/proj';
function transformCoords(coord) {
return transform(coord, 'EPSG:4326', 'EPSG:3857');
}
Для массивов координат требуется рекурсивная трансформация.
Деградированная геометрия — частный случай невалидной структуры:
Проверка площади:
import Polygon from 'ol/geom/Polygon';
function hasArea(polygon) {
return polygon.getArea() > 0;
}
Для линий:
import LineString from 'ol/geom/LineString';
function isDegenerateLine(line) {
const coords = line.getCoordinates();
return coords.every(c => c[0] === coords[0][0] && c[1] === coords[0][1]);
}
Валидация геометрии обычно встраивается в цепочку обработки:
ol/format/*;VectorSource.Пример интеграции:
import VectorSource from 'ol/source/Vector';
function addValidatedFeature(source, feature) {
const geom = feature.getGeometry();
if (!geom) return;
if (geom.getType() === 'Polygon') {
const coords = geom.getCoordinates();
if (hasSelfIntersection(coords[0])) return;
}
source.addFeature(feature);
}
При работе с внешними источниками данных ошибки геометрии неизбежны. Применяются стратегии:
Простейшая стратегия фильтрации:
function filterValidFeatures(features) {
return features.filter(f => {
const geom = f.getGeometry();
return geom && geom.getCoordinates().length > 0;
});
}
При программной генерации часто возникают:
MultiPolygon и Polygon;Особенно критичны операции геометрической генерации:
Каждая из них требует повторной валидации результата.
После трансформаций геометрия может потерять корректность.
import { buffer } from 'ol/extent';
function safeOperation(feature) {
const geom = feature.getGeometry();
const result = geom.buffer(10);
if (!result) return null;
if (result.getCoordinates().length === 0) return null;
feature.setGeometry(result);
return feature;
}
Особое внимание требуется операциям:
simplifybufferintersectionunion (при использовании внешних библиотек)При работе с VectorLayer в OpenLayers валидность
геометрий напрямую влияет на:
Рекомендуется централизованная точка проверки перед добавлением в
VectorSource, а не распределённая логика по компонентам
приложения.
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
const source = new VectorSource({
features: []
});
const layer = new VectorLayer({
source
});