Определение принадлежности точки полигону в OpenLayers опирается на
геометрические операции над объектами ol/geom, где ключевую
роль играет топология координат и корректная работа с проекциями.
Полигон рассматривается как замкнутый набор координатных контуров, а
точка — как упрощённая геометрия с одной парой координат. Проверка
принадлежности сводится к вычислению: лежит ли координата внутри
внешнего кольца полигона и не попадает ли в область внутренних
отверстий.
В OpenLayers полигон задаётся через структуру
ol/geom/Polygon, которая хранит массив колец:
Формат координат:
[
[ [x1, y1], [x2, y2], ... ], // внешний контур
[ [xA, yA], [xB, yB], ... ] // отверстие (опционально)
]
Каждая координата интерпретируется в системе координат карты, чаще
всего EPSG:3857.
Точка задаётся объектом ol/geom/Point:
import Point from 'ol/geom/Point';
const point = new Point([x, y]);
OpenLayers предоставляет методы геометрии, позволяющие выполнять пространственные запросы без внешних библиотек.
intersectsCoordinateНаиболее универсальный вариант — проверка пересечения координаты с геометрией:
import Polygon from 'ol/geom/Polygon';
const polygon = new Polygon([
[
[0, 0],
[10, 0],
[10, 10],
[0, 10],
[0, 0]
]
]);
const coordinate = [5, 5];
const result = polygon.intersectsCoordinate(coordinate);
Если координата находится внутри полигона или на его границе,
результат будет true.
containsCoordinateВ ряде версий OpenLayers используется метод:
polygon.containsCoordinate(coordinate);
Он выполняет более строгую проверку принадлежности внутренней области, исключая некоторые граничные случаи, в зависимости от реализации геометрии.
FeatureВекторная модель OpenLayers строится на ol/Feature, где
геометрия является свойством объекта.
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
const pointFeature = new Feature({
geometry: new Point([5, 5])
});
Полигоны также представлены как Feature:
const polygonFeature = new Feature({
geometry: polygon
});
Проверка принадлежности выполняется через извлечение геометрии:
const pointGeom = pointFeature.getGeometry();
const polygonGeom = polygonFeature.getGeometry();
const coordinate = pointGeom.getCoordinates();
const isInside = polygonGeom.intersectsCoordinate(coordinate);
Ключевой источник ошибок — несовпадение систем координат.
OpenLayers по умолчанию использует EPSG:3857, тогда как
внешние данные часто приходят в EPSG:4326.
Преобразование выполняется через ol/proj:
import { fromLonLat, toLonLat } from 'ol/proj';
const lonLat = [30.5, 50.4];
const projected = fromLonLat(lonLat);
Проверка принадлежности должна выполняться только в одной системе координат:
const polygon = new Polygon([...]); // уже в EPSG:3857
const point = fromLonLat([30.5, 50.4]);
const result = polygon.intersectsCoordinate(point);
Игнорирование преобразования приводит к ложным результатам, особенно при работе с глобальными координатами.
При необходимости независимой логики применяется алгоритм ray casting (пересечение луча).
Идея: проводится горизонтальный луч вправо от точки и считается количество пересечений с рёбрами полигона.
function pointInPolygon(point, ring) {
const x = point[0], y = point[1];
let inside = false;
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
const xi = ring[i][0], yi = ring[i][1];
const xj = ring[j][0], yj = ring[j][1];
const intersect =
((yi > y) !== (yj > y)) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
Для полигона OpenLayers необходимо отдельно учитывать внешнее кольцо и отверстия:
function pointInOlPolygon(point, polygon) {
const rings = polygon.getCoordinates();
const outer = rings[0];
const holes = rings.slice(1);
let inside = pointInPolygon(point, outer);
if (!inside) return false;
for (const hole of holes) {
if (pointInPolygon(point, hole)) {
return false;
}
}
return true;
}
При необходимости расширенной геопространственной аналитики
применяется @turf/boolean-point-in-polygon.
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
import { point, polygon } from '@turf/helpers';
const pt = point([5, 5]);
const poly = polygon([[
[0, 0],
[10, 0],
[10, 10],
[0, 10],
[0, 0]
]]);
const result = booleanPointInPolygon(pt, poly);
В OpenLayers такая проверка часто используется при анализе GeoJSON-данных до их отображения на карте.
Векторная работа часто связана с событиями click или
pointermove.
map.on('click', function (event) {
const coordinate = event.coordinate;
const isInside = polygon.intersectsCoordinate(coordinate);
});
Координата события уже находится в проекции карты, поэтому дополнительное преобразование не требуется.
При анализе массивов точек применяется оптимизация через предварительное ограничение по bounding box.
const extent = polygon.getExtent();
function fastReject(coord) {
return (
coord[0] < extent[0] ||
coord[0] > extent[2] ||
coord[1] < extent[1] ||
coord[1] > extent[3]
);
}
Далее выполняется точная проверка:
if (!fastReject(coord)) {
polygon.intersectsCoordinate(coord);
}
При анализе множества объектов используется обход
VectorSource:
vectorSource.forEachFeature(function (feature) {
const geometry = feature.getGeometry();
const coordinate = pointFeature.getGeometry().getCoordinates();
if (geometry.intersectsCoordinate(coordinate)) {
// объект содержит точку
}
});
Такой подход применяется для пространственного фильтра, кластеризации и поиска объектов в зоне.
Геометрические проверки чувствительны к:
OpenLayers использует плоскую модель вычислений, поэтому при больших масштабах или глобальных координатах возможны искажения.
Часто полигоны приходят в формате GeoJSON:
import GeoJSON from 'ol/format/GeoJSON';
const format = new GeoJSON();
const feature = format.readFeature(geojsonObject);
const geometry = feature.getGeometry();
const isInside = geometry.intersectsCoordinate([x, y]);
GeoJSON автоматически приводится к внутреннему формату OpenLayers, но проекция остаётся критическим параметром:
format.readFeature(geojsonObject, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
Практическая реализация часто включает несколько уровней:
intersectsCoordinatefunction containsPoint(polygon, coord) {
if (!polygon.intersectsCoordinate(coord)) return false;
return polygon.intersectsCoordinate(coord);
}
В более строгих сценариях второй вызов заменяется на точный алгоритм без оптимизаций.
Определение точки в полигоне используется при:
Каждый сценарий требует согласованности геометрий, корректной проекции и выбора между быстрым приближённым методом и точной топологической проверкой.