QGIS

Когда коту делать нечего, он яйца лижет; когда у меня нет срочных дел, я программирую и делаю что-нибудь в сфере своих интересов.

Одной из таких сфер является картография.

Впервые я сделал карту в период работы в ЦПКиО им. М. Горького, потому что работать по большим чертежам неудобно, и хорошо бы иногда делать собственные фрагменты той или иной местности.

Изначально я, конечно, не знал о разных системах координат и переходах из одной в другую, МГГТ и прочих, но постепенно втянулся. Со временем карты пришлось переделать из геоцентрической в нормальную декартову местную систему координат.

О всяких примитивных вещах, типа выдёргивания из кадастрового плана территории квартала координат объектов по регулярным выражениям 🤦, я рассказывать пока не хочу. А вот на другом месте работы я построил карту электросетевых связей объектов на основании табличек отдела электрохозяйства.

На самом деле всё довольно просто.

Для начала заносим в базу нужные нам объекты недвижимости с их геометрией и структурированным адресом, и выгружаем координаты в формате WKT в CSV вместе с адресами. Так проще потому, что база данных объектов у меня была на Drupal & Openlayers, то есть на PHP+MySQL, а QGIS (как и любой другой известный мне картографический софт) подключаться к MySQL и извлекать пространственные данные не умеет. В Drupal такая выгрузка настраивается довольно просто, и CSV скачивается на компьютер просто при обращении по определенному адресу.

На выходе получается приблизительно такой файл формата CSV (разделенный табулятором).

Address Korpus KadNum KadArea WKT
░░.░░░░░░░ ░.░░ стр.16 3 ░░:░░:░░░░░░░:1081 3771,30 POLYGON (…)
░░.░░░░░░░ ░.░░ стр.17 6 ░░:░░:░░░░░░░:1082 1723,60 POLYGON (…)
░░.░░░░░░░ ░.░░ стр.18 112а ░░:░░:░░░░░░░:1033 7881,20 POLYGON (…)
░░.░░░░░░░ ░.░░ стр.19 118 ░░:░░:░░░░░░░:1034 5304,20 POLYGON (…)
░░.░░░░░░░ ░.░░ стр.2 112 ░░:░░:░░░░░░░:1067 9909,80 POLYGON (…)
░░.░░░░░░░ ░.░░ стр.20 26Б ░░:░░:░░░░░░░:1041 349,90 POLYGON (…)
░░.░░░░░░░ ░.░░ стр.21 118А ░░:░░:░░░░░░░:1040 7947,60 POLYGON (…)
/images/2019-11-27_125708.png/images/2019-11-27_125827.png

При загрузке такого CSV в качестве слоя в QGIS мы получаем контуры зданий (из поля WKT в CSV) и связанные с ними адреса.

/images/2019-11-27_130047.png

Таблички от отдела электрохозяйства с перечнями подстанций выглядели приблизительно так:

N TPName Address Inventory
5 ТП-7 (РП 5409) 6 кВ и ТП-7А (РП 5419) 6 кВ ░░.░░░░░░░ ░.░░ стр.26 20123
6 ТП-8 (РП 5424) 6 кВ ░░.░░░░░░░ ░.░░ стр.58 20136
7 ТП-9 (РП 5410) 6 кВ ░░.░░░░░░░ ░.░░ стр.14 20103
8 ТП-11 6 кВ ░░.░░░░░░░ ░.░░ стр.62 20143

Тут, очевидно, необходимо дорабатывать текст до придания ему единообразия (в данном примере адреса мною уже приведены к единообразному формату); к примеру, РП-* вынести в отдельную колонку. Но главное тут есть — привязка адреса здания к подстанции. Формат адреса в этой таблице должен строго соответствовать адресу здания из списка с координатами. Я доработал его следующим образом:

N TPName Address Inventory
5 ТП-7 ░░.░░░░░░░ ░.░░ стр.26 20123
6 ТП-8 ░░.░░░░░░░ ░.░░ стр.58 20136
7 ТП-9 ░░.░░░░░░░ ░.░░ стр.14 20103
8 ТП-11 ░░.░░░░░░░ ░.░░ стр.62 20143

Конечно, в зависимости от потребностей записи «6кВ» и «10кВ», к примеру, можно было бы вынести в отдельную колонку и отображать их на карте, но для примера мы список предельно упростим.

Загружаем его аналогичным образом, однако выбираем отсутствие геометрии, поскольку её в этой таблице просто нет. Картинка ниже сделана до того, как я внёс существенные правки выше, это нужно иметь в виду.

/images/2019-11-27_130139.png

Теперь создадим виртуальный слой.

/images/2019-11-27_131025.png

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

/images/2019-11-27_131934.png/images/2019-11-27_131946.png/images/2019-11-27_132112.png

Запрос:

select Centroid(obj.geometry), obj.Address, tps.Name from obj, tps where obj.Address == tps.Address

Из таблиц obj и tps в новую таблицу мы выбираем поля адреса, имени подстанции и геометрического центра объекта, для которого адрес в таблице зданий совпадает с таблицей трансформаторных подстанций.

/images/2019-11-27_134613.png

Что важно — при редактировании виртуального слоя он каждый раз при нажатии кнопки «Добавить» создаётся заново, и если есть проблемы с системами координат, точки центроидов в видимом поле могут не появиться, и нужно выходить из диалога редактирования виртуального слоя и задавать нужную систему координат вручную. В моём наборе данных использовалась EPSG:4326, та же система будет использоваться и в производных слоях. Чтобы отображать объекты в плоскости, нужно использовать декартову систему координат (МГГТ или любую МСК), или EPSG:3857.

Для созданного виртуального слоя можно и нужно создать подписи, которые будут обозначать подстанции.

Теперь построение связей.

Для начала нужно загрузить CSV «Кабельный журнал высокого напряжения» с атрибутами, который в самом простейшем варианте состоит из двух колонок: пары вида подстанция¹ — подстанция², то есть какая подстанция с какой соединена. Имена подстанций должны соответствовать тем, что указаны в перечне подстанций, иначе их невозможно будет сопоставить.

/images/2019-11-29_141618.png
SELECT SRC, TRGT, make_line(Centroid(objFrom.geometry), centroid(objTo.geometry)) FROM hvolt
JOIN tps tpsFrom  ON hvolt.SRC == tpsFrom.Name
JOIN tps tpsTo    ON hvolt.TRGT == tpsTo.Name
JOIN obj objFrom  ON tpsFrom.Address == objFrom.Address
JOIN obj objTo    ON tpsTo.Address == objTo.Address

В виртуальный слой попадает три колонки: колонки SRC и TRGT из таблицы «Кабельный журнал высокого напряжения», которую для удобства переименовали в hvolt, а в поле геометрии создаваемого объекта попадает результат работы функции, создающей из двух точек линию. Точки выбираются отдельными запросами (tpsFrom + objFrom для исходной точки, tpsTp + objTo для целевой).

Опционально можно создать подписи к генерируемым линиям, например указав concat('← ',TRGT) в поле подписи (Label), тогда рядом с линией будет показываться направление и цель. Конечно, вместо линии можно отрисовывать стрелку.

Я пока не понимаю, возможно ли в QGis рисовать дуги при генерации геометрии, потому что прямые линии не вполне удобны.

В итоге это может выглядеть так:

/images/2019-11-29_144053.png

Дополнительные слои (например, карта линий низкого напряжения) добавляются аналогично.