Точки — объекты Point
GeoJSON-точка выглядит так:
{ "type": "Point", "coordinates": [-80.1347334, 25.7663562] }
Эта точка представляет парк в Майами-Бич, штат Флорида, США. Визуализировать эту точку на карте легко можно с помощью проекта geojson.io.
Точка на карте
Важно отметить, что координата в свойстве coordinates
записывается в формате [lng, lat]
. Долгота в GeoJSON идёт перед широтой. Это так из-за того, что долгота представляет направление «восток-запад» (ось x
на типичной карте), а широта — направление «север-юг» (ось y
на типичной карте). Авторы GeoJSON стремились к сохранению порядка координат x, y
.
Типичный пример использования точек GeoJSON — геокодирование — преобразование адресов наподобие «429 Lenox Ave, Miami Beach, FL» в координаты, выраженные долготой и широтой. Например, мы пользуемся API геокодирования Mapbox. Для обращения к этому API нужно выполнить HTTP-запрос к следующей конечной точке:
https://api.mapbox.com/geocoding/v5/mapbox.places/429%20lenox%20ave%20miami.json?access_token=pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g&cachebuster=1581993735895&autocomplete=true
В ответ придёт такой код:
{"type":"FeatureCollection","query":["429","lenox","ave","miami"],"features":[{"id":"address.8052276751051244","type":"Feature","place_type":["address"],"relevance":1,"properties":{"accuracy":"rooftop"},"text":"Lenox Avenue","place_name":"429 Lenox Avenue, Miami Beach, Florida 33139, United States","center":[-80.139145,25.77409],"geometry":{"type":"Point","coordinates":[-80.139145,25.77409]}, ...}
Если присмотреться к ответу, то окажется, что features[0].geometry
в JSON-коде — это GeoJSON-точка:
{"type":"Point","coordinates":[-80.139145,25.77409]}
Визуализация координат
API статических карт Mapbox — это отличный инструмент для вывода точек на картах. Ниже показан скрипт, который декодирует переданную ему строку и возвращает URL на изображение, которое показывает первый результат поиска.
const axios = require('axios'); async function search(str) { const geocoderUrl = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + encodeURIComponent(str) + '.json?access_token=' + 'pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g'; const res = await axios.get(geocoderUrl).then(res => res.data); const point = res.features[0].geometry; return 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/' + 'pin-l-1+333(' + point.coordinates[0] + ',' + point.coordinates[1] + ')/' + point.coordinates[0] + ',' + point.coordinates[1] + ',14.25,0,0/600x600/' + '?access_token=pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g'; } search('429 Lenox Ave, Miami Beach').then(res => console.log(res));
Пример визуализации точки на карте
Линии — объекты LineString
В GeoJSON линии, объекты LineString
, представляют массивы координат, описывающие линию на карте. Ниже показан GeoJSON-объект LineString
, представляющий приблизительную границу между штатами Калифорния и Орегон в США:
{ "type": "LineString", "coordinates": [[-124.2, 42], [-120, 42]] }
Визуализация объекта LineString на карте
Линии, при использовании API навигации наподобие Mapbox, применяются для визуализации поэтапного пути между двумя точками. Один из способов представления автомобильного пути из точки [-80.139145,25.77409]
(офис WeWork в Майами-Бич) до точки [-80.2752743,25.7938434]
(международный аэропорт Майами) заключается в использовании GeoJSON-объекта LineString
:
{ "type": "LineString", "coordinates": [ [-80.139153, 25.774281], [-80.13829, 25.774307], [-80.142029, 25.774479], [-80.148438, 25.772148], [-80.151237, 25.772232], [-80.172043, 25.78116], [-80.177322, 25.787195], [-80.185326, 25.787212], [-80.189804, 25.785891], [-80.19268, 25.785954], [-80.202301, 25.789175], [-80.207954, 25.788721], [-80.223, 25.782646], [-80.231026, 25.78261], [-80.238007, 25.784889], [-80.246025, 25.784403], [-80.249611, 25.785175], [-80.253166, 25.786049], [-80.259262, 25.786324], [-80.264038, 25.786186], [-80.264221, 25.787256], [-80.264214, 25.791618], [-80.264221, 25.792633], [-80.264069, 25.795443], [-80.263397, 25.795652], [-80.263786, 25.794928], [-80.267723, 25.794926], [-80.271141, 25.794859], [-80.273163, 25.795704], [-80.275009, 25.796482], [-80.277481, 25.796461], [-80.278435, 25.795622], [-80.278061, 25.794088], [-80.275276, 25.793804] ] }
Объекты LineString
, представляющие собой некие маршруты, могут быть очень сложными. Вышеприведённый объект, например, описывает короткую 15-минутную поездку. Вот как всё это выглядит на карте.
Путь из одной точки в другую
Вот — простой скрипт, который возвращает LineString
-представление пути между 2 точками с использованием API directions
Mapbox.
const axios = require('axios'); async function directions(fromPt, toPt) { const fromCoords = fromPt.coordinates.join(','); const toCoords = toPt.coordinates.join(','); const directionsUrl = 'https://api.mapbox.com/directions/v5/mapbox/driving/' + fromCoords + ';' + toCoords + '?' + 'geometries=geojson&' + 'access_token=pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g'; const res = await axios.get(directionsUrl).then(res => res.data); return res.routes[0].geometry; } const wework = { type: 'Point', coordinates: [-80.139145,25.77409] }; const airport = { type: 'Point', coordinates: [-80.2752743,25.7938434] }; directions(wework, airport).then(res => { console.log(res); });
Полигоны — объекты Polygon
GeoJSON-полигоны, объекты Polygon
, используются для описания замкнутых областей на картах. Это могут быть области, имеющие форму треугольника, квадрата, двенадцатиугольника, или любой другой фигуры с фиксированным количеством сторон. Например, следующий GeoJSON-объект грубо описывает границы штата Колорадо в США:
{ "type": "Polygon", "coordinates": [[ [-109, 41], [-102, 41], [-102, 37], [-109, 37], [-109, 41] ]] }
Визуализация полигона на карте
GeoJSON-полигоны могут использоваться для описания очень сложных форм. Например, некоторое время в Uber использовался единственный GeoJSON-полигон, включающий в себя все 3 основных аэропорта области залива Сан-Франциско.
Сложный GeoJSON-полигон
Правда, надо отметить, GeoJSON-полигоны не могут представлять окружности и эллипсы.
Для чего используются полигоны? Обычно — для описания геозон. Например, представьте себе, что работаете в Uber или в Lyft. Вам нужно показать пользователям, заказывающим поездки из аэропорта, особый экран. Для того чтобы это сделать, нужно будет узнать, находится ли точка, из которой заказывают поездку, в пределах полигона, описывающего аэропорт (или несколько аэропортов как на предыдущем рисунке).
Один из способов проверки нахождения GeoJSON-точки в пределах полигона заключается в использовании npm-модуля Turf. Модуль @turf/boolean-point-in-polygon
позволяет узнать о том, находится ли точка в пределах полигона.
const pointInPolygon = require('@turf/boolean-point-in-polygon').default; const colorado = { "type": "Polygon", "coordinates": [[ [-109, 41], [-102, 41], [-102, 37], [-109, 37], [-109, 41] ]] }; const denver = { "type": "Point", "coordinates": [-104.9951943, 39.7645187] }; const sanFrancisco = { "type": "Point", "coordinates": [-122.4726194, 37.7577627] }; // true console.log(pointInPolygon(denver, colorado)); // false console.log(pointInPolygon(sanFrancisco, colorado));
Пакет Turf позволяет узнать о том, находится ли точка в пределах полигона, пользуясь средой Node.js. Но что если нас интересует получение таких же сведений путём выполнения запросов к базе данных? В таком случае стоит знать о том, что встроенный оператор MongoDB $geoIntersects
поддерживает GeoJSON. Поэтому, например, можно написать запрос, который позволяет выяснить, какому штату США соответствует некая точка на карте:
const mongoose = require('mongoose'); run().catch(err => console.log(err)); async function run() { await mongoose.connect('mongodb://localhost:27017/geotest', { useNewUrlParser: true, useUnifiedTopology: true }); await mongoose.connection.dropDatabase(); const State = mongoose.model('State', mongoose.Schema({ name: String, location: mongoose.Schema({ type: String, coordinates: [[[Number]]] }) })); const colorado = await State.create({ name: 'Colorado', location: { "type": "Polygon", "coordinates": [[ [-109, 41], [-102, 41], [-102, 37], [-109, 37], [-109, 41] ]] } }); const denver = { "type": "Point", "coordinates": [-104.9951943, 39.7645187] }; const sanFrancisco = { "type": "Point", "coordinates": [-122.4726194, 37.7577627] }; // В каком штате находится Денвер? let res = await State.findOne({ location: { $geoIntersects: { $geometry: denver } } }); res.name; // Колорадо // В каком штате находится Сан-Франциско? res = await State.findOne({ location: { $geoIntersects: { $geometry: sanFrancisco } } }); res; // null }
Итоги
GeoJSON — это не только хранение координат точек. В этом формате можно хранить пути. С использованием GeoJSON-данных можно выяснить момент попадания пользователя в геозону. А если нужно, то GeoJSON даже позволяет создавать изохроны. Вокруг формата GeoJSON сформировался набор отличных инструментов. Так, ресурс geojson.io позволяет выполнять простые визуализации координат на карте. Проект Mapbox даёт доступ к продвинутым географическим API. Пакет Turf позволяет выполнять геопространственные вычисления в браузерах и в среде Node.js.
MongoDB поддерживает запросы, связанные с географическими данными. И если вы храните географические координаты точек в виде пар значений, не пользуясь форматом GeoJSON, это значит, что вы упускаете возможность воспользоваться некоторыми замечательными инструментами разработки.
Уважаемые читатели! Пользуетесь ли вы форматом GeoJSON?
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/489828/
Добавить комментарий