О ГИС

2018-08-11

ГИС — это Географическая Информационная Система. Именно поэтому 2ГИС так называется. Это и геоинформационная система, то есть карта, и Городская Информационная Система, то есть справочник организаций.

Но 2ГИС — это, так сказать, read-only GIS. Вы можете посмотреть, поискать, построить маршрут. Но ничего не можете менять.

В серьёзном взрослом мире нужно таки менять. Рисовать карты. Рисовать что-нибудь на картах. Типичный пример: OpenStreetMap. Это общенародная карта, где всякий может подрисовать свой гараж или тропинку в саду.

Но OSM собирает только картографические данные. А иногда нужно просто нарисовать что-то в привязке к местности. Я не геодезист и не архитектор, но, подозреваю, этим людям постоянно нужно что-то проектировать именно на карте. И для них существуют специальные GIS программы. Так же как для инженеров/чертёжников существуют CAD.

Хотел сказать, что единственной вменяемой свободной GIS является QGIS. Именно ею я и пользовался. Но Википедия говорит, что десятки их. Десятки только свободных. Но я всё равно рекомендую QGIS.

QGIS splashscreen

(На самом деле уже релизнулась версия 3.2, но во второй ветке сплешскрины красивее.)

Для чего вам может понадобиться ГИС? Почти для всего, где вам нужна будет карта. И надо на этой карте что-то нарисовать. Наложить треки, расставить точки, подсчитать расстояния. Да хотя бы редактировать OSM. Простые гугло/яндекс карты далеко не всё это могут.

Например, такая задача. Есть местность, где производятся некие инженерно-копательные работы. Вам, как программисту, нужно отобразить на карте план этих работ, дополнить всякими метками и графиками. В веб-приложении. И чтобы было сэкси.

Как бы не проблема. Есть Mapbox или Leaflet. Они могут отображать на своих слоях любой GeoJSON. Понятно, что GeoJSON можно просто сохранить в БД и выдавать по запросу. Или можно генерировать его из каких-то пространственных данных в другом формате.

Но где взять эти пространственные данные? Где взять эти точки, линии и многоугольники, с широтой и долготой по WGS 84? Если всё, что у вас есть — некий план, нарисованный в Paint. Хорошо хоть, в масштабе.

QGIS screenshot

Открываем QGIS и создаём новый проект...

Технически QGIS проект — это просто каталог слоёв. В виде файла с расширением .qgs в формате XML. А сами слои — это уже отдельные файлы, и не только файлы. Слои можно упорядочивать, группировать, скрывать или отображать, добавлять новые, удалять из проекта. Можно редактировать, но не все.

Условно можно выделить три типа слоёв.

Векторные слои. Самые важные, ибо вся работа, как правило, делается в них. Эти самые точки, линии да многоугольники — есть векторные сущности.

Векторные данные можно загружать из БД. Из PostgreSQL, возможно с PostGIS, хотя он умеет пространственные данные и просто из коробки. Из SpatiaLite — геопространственного расширения SQLite.

Векторные данные можно брать из файлов. Тот же GeoJSON сгодится. Треки в виде GPX файлов. Можно даже импортировать настоящие автокадовые чертежи в DWG. Только сначала нужно их конвертировать в DXF.

Если не связываться с базами данных, то самый ходовой формат для векторного слоя — так называемые Shapefiles. В одном Shapefile можно хранить только один тип данных: точки, линии или полигоны. QGIS умеет редактировать shapefiles в полном объеме.

Технически это на самом деле несколько файлов. .shp — бинарный файл с географическими координатами. .dbf — табличка dBase со свойствами наших географических примитивов. И ещё несколько для всяких связей, индексов и описания используемой системы координат.

Да, добавляешь в проект десяток слоёв, и вот уже в папочке проекта завалялась сотня странных файлов. А учитывая, что один и тот же файл можно умудриться включить в проект в виде разных слоёв, например, с разным отображением, то вообще кошмар.

Shapefile vs

Второй тип слоёв: растровые. Обычные картинки из пикселей. Их тоже можно натянуть на карту. Обычно предпочитают TIFF, потому что в него можно включить метаинформацию о тех же координатах. А вот рядом с PNG могут снова образоваться вспомогательные файлы.

Третий тип слоёв: тайловые подложки. Если рисуем на местности, нужно эту местность для начала как-то представить. И, с помощью плагина OpenLayers мы можем добавить в наш проект слой с картинкой из OpenStreetMap, или карт Google, или даже спутниковых снимков от Bing или снова от Google. Это будет работать как обычные веб-карты (только медленнее), тайлы будут качаться из интернетов.

Шаг нулевой выполнен. Добавлен нижний слой с тайлами из OpenStreetMap.

Плагины. QGIS написан на PyQt. И плагины к нему пишутся на Python. Тысячи их. Собственно, весь QGIS — это сборище плагинов.

Шаг первый. Мы нашли местность. Теперь на эту местность нужно натянуть план из растровой картинки. Это называется Georeferencing.

Дело в том, что естественными координатами растрового изображения являются координаты его пикселей. Столько-то пикселей по горизонтали, столько-то по вертикали. Это ещё и целые числа. Это соотносится с нашими вещественными широтой и долготой, которые в градусах глобуса, почти никак. Вот координаты в пикселях и нужно преобразовать в координаты в градусах на глобусе. И хорошо ещё, если обойдётся линейным преобразованием.

Тут нужно ещё помнить, что глобусы тоже бывают разные. Но, слава богу, в этих наших веб-картах, с проекцией Меркатора, принята система координат под названием EPSG:3857 (она же "WGS 84 / Pseudo-Mercator"). Только, внимание, единица изменения тут — метры! А если нужны градусы (а они нужны), но нужны другие координаты: EPSG:4326 (они же просто "WGS 84"). Причём в GeoJSON принято сию систему координат (CRS — Coordinate Reference System) называть urn:ogc:def:crs:OGC:1.3:CRS84.

У каждого слоя может быть своя система координат. Слава богу, QGIS умеет самостоятельно всё пересчитывать на лету. Постарайтесь не запутаться. И помните, что первая координата: X — это долгота (longitude), потому что по горизонтали. А вторая координата: Y — это широта (latitude), потому что по вертикали.

Поехали дальше. Нужно сделать georeferencing растровой картинки. Смысл в том, чтобы сопоставить некоторые референсные точки на картинке (в пикселях) с точками на карте (в широте и долготе). Двух точек достаточно для линейного преобразования. Но лучше расставить больше точек, чтобы сгладить погрешности, да и попробовать что-нибудь нелинейное. Как правило стоит обозначить что-нибудь по углам картинки, и ещё что-нибудь в середине.

Как нам это сделать? Я нашёл аж три способа.

Номер раз. Стандартный плагин Georeferencer GDAL. Eго не нужно скачивать, достаточно просто включить. Даёт, пожалуй, наиболее точный результат. При точных входных данных, конечно. Умеет красивые нелинейные преобразования. Если у вас на картинке есть линии, которые должны быть соответствующими линиями на карте, у вас есть неплохой шанс точно натянуть картинку на эти линии.

Алгоритм работы такой. В отдельном окошке загружаем картинку. Затем тыкаем на точку картинки и задаём координаты этой точки на карте. Для поиска координат на карте пригодится другой стандартный плагин Coordinate Capture. Помните, X — это долгота, а Y — это широта.

Georeferencing points

Когда мы натыкали достаточно точек, и сохранили их в отдельном файлике для этой картинки, можно попробовать выгнуть картинку, сохранить выгнутую, и добавить её слоем в наш проект. Можно выбрать несколько видов трансформации. Мне больше всего понравился "Projective". Это линейная трансформация, то есть она не изогнёт картинку дугой. Это линейная трансформация в трёх изменениях, то есть двумерная картинка обрабатывается матрицей три на три, и получается какая угодно наклонная проекция на плоскость карты. Получается неплохо.

Georeferencing transformations

Если результат нас не устраивает, удаляем слой из проекта, и возвращаемся к проставлению дополнительных опорных точек, или даже удалению лишних. Не очень интерактивненько.

Способ номер два. Плагин Freehand raster georeferencer. Как понятно из названия, всё придётся делать руками. Сюда сместить, тут наклонить, тут поднянуть. Прямо таскаете картинку (её лучше сделать полупрозрачной) по карте, пока не ляжет нормально. Получается быстро. Кривые картинки мостить удобнее. Но, конечно, никакой суперточности. Для нашего плана из Paint — самое то, пожалуй.

Freehand georeferencer

Способ номер три. Плагин Raster Bender. Плагин экспериментальный, так что не забудьте разрешить установку экспериментальных плагинов. Им я так и не воспользовался, извините. Но иконка зачотная.

Bender

Зато я воспользовался его ближайшим родственником: плагином Vector Bender.

Дело в том, что ещё мне понадобилось натянуть на карту чертёж в том самом DWG. То есть сделать georeferencing для векторных данных. И если для растра есть несколько вполне приличных способов, то для вектора всё как-то не очень. Из более-менее стандартных средств есть разве что Affine Transformations. Но там нужно матрицу трансформации тупо задать руками. А откуда взять цифры? Облазать полкарты с линейкой? И всё равно промазать?

Вот тут Vector Bender и пригодился. Он тоже экспериментальный, так что будьте осторожны. И он не то, чтобы сильно удобный в использовании.

В процессе создаётся целый новый слой. С прямыми. Которые обозначают векторы трансформации. То есть нужно указать, какая точка куда перемещается. А потом переместить. А потом ещё указать, если промахнулись.

В отличие от штатного растрового Georeferencer, Vector Bender определяет тип трансформации по количеству векторов. Линейная будет, если будет задано ровно два вектора перемещения. Это не удобно. А если задать больше, он будет править геометрию. Очень локально, пытаясь прилепить вот эту ближайшую точку вот сюда.

Ладно. Картинку на карту натянули. Где нам взять GeoJSON? Да просто обвести картинку. Создать новый векторый слой (в Shapefile), и натыкать в нём точек, если нужно пометить точки. Или нарисовать линий, если нужно обвести линии. А потом этот слой сохранить в GeoJSON.

Не забудьте указать EPSG:4326 при сохранении. И выставьте точность в шесть знаков после запятой. Квадриллионные доли градуса, которые предлагаются по умолчанию, вам не нужны.

Ну и всё. Извините, что не прикладываю скриншоты со своего QGISа. Ибо NDA.