СТАТЬЯ

Построение и использование топологий

Из PostGIS в действии, третье издание Лео С. Хсу и Регины О. Обе

В этой статье вы узнаете, что такое топология, как построить топологию с нуля и как использовать общедоступные геометрические данные.

Получите скидку 40 % на PostGIS в действии, третье издание, введя fccobe в поле кода скидки при оформлении заказа на сайте manning.com.

Топологическое представление признает, что в действительности геометрические элементы редко существуют независимо друг от друга. Когда вы смотрите на большие мегаполисы с самолета, вы видите лабиринт улиц, очерчивающих кварталы, переплетенные между собой. В простой геометрической модели вы можете использовать линии для представления улиц и многоугольники для представления кварталов. Но как только вы разметите улицы, вы точно знаете, где будут ваши кварталы. Необходимость создавать полигоны для блоков — это упражнение на избыточность. Поздравляем, вы открыли топологию.

Мы будем работать с одним набором примеров. Это будет очень просто, создано без загрузки данных. Этот набор примеров даст вам представление о том, как создаются и организуются топологии.

Мы упаковали схему ch13_staging как часть загрузки этой главы (www.postgis.us/chapterch13a_topologyedition_3) и загрузили в таблицы cityboundary, окрестности и streetcenterlines. Схема ch13 содержит таблицы топогеометрии для этой главы.

Что такое топология

Поверхность земли конечна. У нас есть около 196,9 миллионов квадратных миль (510,1 миллиона квадратных километров), включая воду. Люди территориальны, поэтому мы разделили всю землю на страны, большие и маленькие. За исключением Антарктиды и нескольких спорных зон, в перемещении границы страны участвуют как минимум две страны. Железный закон географии гласит, что когда одна страна получает землю, другая должна ее уступить. Эта земельная игра с нулевой суммой является результатом того, что люди создали страны, которые являются коллективно исчерпывающими и взаимоисключающими на земле.

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

Рассмотрим другой пример. В 1790 году Конгресс США создал Вашингтон из земель, уступленных соседними штатами. Район разделен на четыре квадранта с двумя перпендикулярными осями, расходящимися от зданий Капитолия. Квадранты названы соответствующим образом: северо-запад, северо-восток, юго-запад и юго-восток. Предположим, что в духе равенства Конгресс решил сделать все квадранты одной площадью. Это означало бы перемещение центра осей на север и запад. Если бы вы использовали топологию в модели, эта реорганизация сводилась бы не более чем к перемещению одной точки. При смещении этой точки ваши линии (оси) будут следовать за ней, а многоугольники, образующие квадранты, будут либо сдуваться, либо надуваться. Всего этого можно добиться, просто переместив точку!

В этом сила топологии: определяя набор правил взаимосвязи геометрий, вы избавляете себя от необходимости заново осматривать весь ландшафт всякий раз, когда вносите малейшие изменения.

В PostGIS существует три вида представления векторных данных. Существует более стандартная модель геометрии, в которой каждая геометрия представлена ​​как отдельная единица. В геометрической модели общие элементы, такие как границы массивов суши, дублируются в каждой геометрии. Существует географическая модель, которая так же, как и геометрическая модель, рассматривает каждую часть пространства как отдельные единицы, а границы дублируются, но рассматривает эти единицы в сфероидальном пространстве. Кроме того, есть топологическая модель, которая заимствует двумерное представление о мире из геометрии, но с одним ключевым отличием. В топологической модели общие границы и области сохраняются один раз в базе данных и связаны с геометрией, имеющей общую границу. Эти геометрии со связанными ребрами называются топогеомами.

Это имеет несколько преимуществ:

  • Если вы упростите объект для распространения, упрощенные края по-прежнему будут общими, так что вы не получите перекрытий или пробелов, которых раньше не было.
  • Если у вас есть набор объектов, таких как здания, районы или земельные участки, которые не должны перекрываться, эти проблемы легче обнаружить и предотвратить в топологической модели.

Теперь, когда у вас есть свежее представление о топологиях, мы перейдем к построению топологий с помощью функций топологии PostGIS.

Использование топологий

Топология — это совершенно иной подход к пространственным характеристикам, чем геометрия. Вспомните свой первый курс геометрии: в евклидовой геометрии точки, линии и многоугольники не имели системы координат в качестве фона. Вы заботились не об абсолютном измерении вещей, а об отношениях между ними. Модель топологии в некотором роде возвращает нас к классической геометрии, где вы описываете, как взаимодействуют две свободные геометрии, не принимая во внимание системы координат.

Поскольку топология ГИС является результатом теории графов, она использует другой набор терминов. Во всех смыслах и целях вы можете рассматривать точку в геометрии как узел в топологии, а линию — как ребро и многоугольник в качестве лица. В совокупности узлы, ребра и грани являются топологическими примитивами, используемыми вместо геометрии.

ПРИМЕЧАНИЕ. Мы используем термин топология для обозначения как области изучения топологии, так и топологии сети.

Установка расширения топологии

Прежде чем вы сможете создать топологию, вы должны убедиться, что у вас установлено расширение топологии. Если вы не уверены, найдите схему с именем topology в своей базе данных. Эта схема содержит функции, используемые для создания топологий, а также таблицу каталога топологии. Если он отсутствует, вы еще не установили расширение. Расширения должны устанавливаться отдельно для каждой базы данных.

CREATE EXTENSION postgis_topology;

Как часть установки топологии, PostGIS добавляет схему topology в базу данных search_path. Это означает, что вы можете ссылаться на функции топологии без явного добавления topology.

В некоторых случаях роль, под которой вы вошли в систему, может иметь собственную настройку search_path, которая переопределяет настройку базы данных search_path. Прежде чем продолжить, убедитесь, что topology является частью вашего search_path, выполнив следующую инструкцию SQL:

SHOW search_path;

Если вы не видите схему topology в списке search_path, отключитесь от базы данных и снова подключитесь.

Как только это будет сделано, вы можете создать топологию.

Создание топологии

В этом разделе вы создадите стилизованную топологию на основе прямоугольного штата Колорадо с SRID 4326. В следующем листинге показано, как можно создать топологию.

SELECT CreateTopology('ch13a_topology',4326);

После выполнения вышеупомянутого SQL вы заметите новую схему с именем ch13a_topology. В таблице каталога topology.topology появится новая запись, регистрирующая новую топологию. Заглянув внутрь схемы ch13a_topology, вы увидите четыре новые таблицы, ожидающие данных: node, edge_data, face и ratio.

PostGIS использует отдельную схему для размещения каждой топологической сети — в данном случае ch13a_topology. Выбранный SRID применяется ко всем таблицам в схеме и ко всем столбцам топогеометрии, которые будут использовать схему ch13a_topology. Поскольку топология связана с отношениями между геометриями, разные SRID не имеют смысла.

В каждой топологии вы всегда найдете четыре таблицы: node, edge_data, face и ratio. Первые три являются просто топонимами для точек, линий и полигонов. Из этих трех таблиц для хранения примитивов edge_data содержит всю информацию для построения сети. Когда вы начнете строить пространственные объекты из примитивов топологии, отношения каждого из этих пространственных объектов с топологией будут находиться в таблице.

Для Колорадо вы можете начать с добавления строк, образующих четыре границы штата, с помощью функции TopoGeo_AddLineString, как показано в листинге 1.

Листинг 1. Построение топологической сети Колорадо

SELECT TopoGeo_AddLineString(
     'ch13a_topology',
         ST_GeomFromText(
           'LINESTRING(
                    -109.05304 39.195013,
                    -109.05304 41.000889,
                    -104.897461 40.996484
           )',
           4326
     )
 );
  
 SELECT TopoGeo_AddLineString(
         'ch13a_topology',
         ST_GeomFromText(
           'LINESTRING(
               -104.897461 40.996484,
               -102.051744 40.996484,
               -102.051744 40.003029
           )',
           4326
     )
 );
  
 SELECT TopoGeo_AddLineString(
         'ch13a_topology',
         ST_GeomFromText(
           'LINESTRING(
               -102.051744 40.003029,
               -102.04874 36.992682,
               -104.48204 36.992682
           )',
           4326
     )
 );
  
 SELECT TopoGeo_AddLineString(
         'ch13a_topology',
         ST_GeomFromText(
           'LINESTRING(
               -104.48204 36.992682,
               -109.045226 36.999077,
               -109.05304 39.195013
           )',
           4326
     )
  );

Чтобы убедиться, что вы все набрали или скопировали правильно, выполните следующий SQL:

SELECT ST_GetFaceGeometry('ch13a_topology',1);

Если вы посмотрите на вывод средства просмотра геометрии в pgAdmin, вы должны увидеть то, что показано на рисунке 1.

Весь штат Колорадо представляет собой одно большое лицо, представляющее собой идеально прямоугольный многоугольник.

Загляните внутрь таблиц после запуска кода из листинга 1, и вы увидите четыре новых ребра, четыре новых узла и одну новую грань. Функция TopoGeo_AddLineString автоматически генерирует топологическую сеть, используя данные ребер, и заполняет узлы и грани. Теперь у вас есть топология прямоугольного контура Колорадо.

Две основные автомагистрали между штатами пересекают штат от границы до границы: I-25 проходит с севера на юг, а I-70 - с запада на восток. Вы можете добавить I-70 с помощью следующего кода.

Листинг 2. Добавление шоссе I-70

SELECT TopoGeo_AddLineString(
         'ch13a_topology',
         ST_GeomFromText(
           'LINESTRING(
                    -109.05304 39.195013,
                    -108.555908 39.108751,
                    -105.021057 39.717751,
                    -102.051744 40.003029
           )',
           4326
     )
  );

После успешного добавления I-70 SELECT вернет идентификационный номер нового ребра. Вы должны увидеть число 5 в выводе.

Далее добавляем I-25.

Листинг 3. Добавление шоссе I-25

SELECT TopoGeo_AddLineString(
         'ch13a_topology',
         ST_GeomFromText(
           'LINESTRING(
                    -104.897461 40.996484,
                    -105.021057 39.717751,
                    -104.798584 38.814031,
                    -104.48204 36.992682
           )',
           4326
     )
 );

Поскольку вы сначала добавили I-70, а затем I-25, последний разделит I-70 пополам, создав для себя два ребра и разбив I-70 на два ребра. Выходные данные вернут идентификационные номера двух новых ребер для I-25: 7 и 8.

На этом этапе будет полезна диаграмма. Мы использовали QGIS PostGIS Topology Viewer для создания рисунка 2, на котором показаны четыре идентификатора лица, восемь идентификаторов ребер и пять узлов (каждый из которых использует свой стиль чисел).

I-25 (ребра 8, 7 с узлами 2, 5, 4) проходит с севера на юг. I-70 (ребра 5, 6 с узлами 1, 5, 3) проходит с запада на восток. Две автомагистрали пересекаются в столице штата Денвере (узел 5).

Добавление автомагистралей разделило оригинальный односторонний Колорадо на четыре стороны. Еще раз внимательно посмотрите на таблицы: PostGIS автоматически реорганизовал вашу топологию. Угловые точки больше не являются узлами, а просто вершинами, очерчивающими ребро. PostGIS добавил узел для Денвера, где пересекаются два края шоссе.

Мы смоделировали шоссе с изломами. Для I-25 излом находится в Колорадо-Спрингс. Для I-70 излом находится на Гранд-Джанкшен. Эти изломы — просто вершины, используемые для уточнения геометрии; они не играют никакой роли в отношениях. Таким образом, они не являются узлами. Ребра пересекаются только в узлах.

Теперь у вас есть в общей сложности восемь ребер. Две автомагистрали делят Колорадо на четыре отдельных многоугольника или грани. Добавление шоссе I-25 разделило нашу первоначальную одностороннюю I-70 (ребро 5) на два ребра (5 и 6).

Если вы посмотрите в таблицу лиц, используя приведенный ниже запрос, вы увидите каждое из перечисленных лиц, а также их mbr (минимальный ограничивающий прямоугольник), который является просто ограничивающим прямоугольником лица. Таблица граней не хранит фактические полигоны, потому что все данные, необходимые для их получения, можно найти в таблице edge_data. Эта методология хранения соответствует принципу хранения данных только в одном месте. Как и прежде, вы используете функцию ST_GetFaceGeometry для просмотра фактической геометрии грани.

SELECT face_id, mbr,
 ST_GetFaceGeometry('ch13a_topology',face_id) AS geom ❶
 FROM ch13a_topology.face
 WHERE face_id > 0; ❷

Вернуть геометрию лица

Исключить универсальную грань без геометрии

Вывод столбца geom в приведенном выше запросе показан на рис. 3. Запрос рассматривает только неуниверсальные грани. Универсальное лицо всегда имеет идентификатор лица 0 и представляет ту часть, которая не является частью топологии, поэтому всегда пуста.

представление края и edge_data

Представление edge — это представление, содержащее подмножество столбцов таблицы edge_data. Таблица edge_data содержит дополнительные столбцы, не определенные в спецификации топологии OGC, но используемые внутри топологии PostGIS. Для общего использования и для соответствия стандартам топологии OGC следует использовать представление edge вместо прямого запроса таблицы edge_data.

Помните, что топология связана не с описанием геометрии, а с тем, как они связаны. Удаление всех лишних вершин в Колорадо создает схему скелетной сети, которую вы можете видеть на рисунке 4.

Вы можете увидеть ребра, составляющие топологию, запросив таблицу edge_data, используя листинг 4.

Листинг 4. Запрос edge_data

SELECT *
 FROM ch13a_topology.edge_data
 ORDER BY edge_id;

Результат листинга 4 показан на рисунке 5, где показано содержимое таблицы edge_data на основе упрощенной топологии.

Не пугайтесь, если ваш вывод немного отличается от приведенного ниже. Однако на этом этапе у вас должно быть 8 ребер.

Тип топогеометрии

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

Допустим, вы хотите собрать четыре ребра, образующие шоссе в модели Колорадо. Вы можете начать с создания новой таблицы для хранения топогеометрии, как показано в листинге 5. В эту таблицу вы можете добавить столбец topogeometry, используя функцию PostGIS AddTopoGeometryColumn. Вы должны всегда использовать функцию AddTopoGeometryColumn для создания новых столбцов, потому что она заботится о регистрации нового столбца topogeometry в таблице topology.layer.

Листинг 5. Создание таблицы для хранения автомагистралей и определение столбца топогеометрии

CREATE TABLE ch13.highways_topo (highway varchar(20) PRIMARY KEY);
 SELECT AddTopoGeometryColumn(
     'ch13a_topology',
     'ch13',
     'highways_topo',
     'topo',
     'LINESTRING'
 );

После запуска предыдущего кода вы должны увидеть новую запись в таблице topology.layer. AddTopoGeometryColumn вернет автоматически назначенный идентификатор нового слоя. Имейте в виду, что топогеометрия всегда привязана к слою.

Получив столбец topogeometry, вы можете добавить шоссе I-70 с помощью функции CreateTopoGeom, как показано в листинге 6.

Листинг 6. Определение топогеометрии I-70 с помощью CreateTopoGeom

INSERT INTO ch13.highways_topo (highway, topo)
 VALUES (
     'I70',
     CreateTopoGeom( ❶
         'ch13a_topology',
         2, ❷
         1, ❸
         '{{5,2},{6,2}}'::topoelementarray ❹
     )
 );

Определить запись для I-70, где элементы топологии формируются из ch13a_topology

Тип топогеомы: 2 = линейный

Идентификатор слоя, которому принадлежит эта топогеома. Это число возвращается при определении столбца топогеомы.

Элементы, составляющие этот топогеом. Каждый элемент в массиве состоит из идентификатора элемента и типа элемента (1 = узел, 2 = ребро, 3 = грань). В этом примере все элементы являются ребрами.

При определении нового столбца топогеометрии необходимо обозначить тип топогеометрии одним из следующих номеров: 1 = точечный, 2 = линейный, 3 = площадной. В случае топогеометрии многоугольники и мультиполигоны объединяются в площадной тип, точки и мультиточки — точечный тип, а линии и мультилинии — линейный тип.

Топогеометрия реализована в виде домена базы данных, состоящего из 4 элементов. Вы можете увидеть воплощение с помощью следующего запроса:

SELECT highway, topo, (topo).*
 FROM ch13.highways_topo WHERE highway = 'I70';

Вывод приведенных выше списков:

highway |   topo    | topology_id | layer_id | id | type
 ---------+-----------+-------------+----------+----+------
  I70     | (1,1,1,2) |           1 |        1 |  1 |    2
 (1 row)

Как видите, расширение (topo).* перечисляет в виде столбцов части, составляющие топогеометрию. Первый элемент — это топология, к которой принадлежит топогеометрия. Второй элемент — это layer, к которому принадлежит топогеометрия, идентификатор слоя, назначенный столбцу ch13.highways_topo.topo при добавлении столбца. Третий элемент — это идентификатор топогеометрии в таблице схемы ch13a_topology relation в столбце topogeo_id. Наконец, четвертый элемент в данном случае имеет тип 2 = lineal.

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

Листинг 7. Определение топогеометрии с помощью toTopoGeom

INSERT INTO ch13.highways_topo (highway, topo)
 SELECT
     'I25',
         toTopoGeom( ❶
           ST_GeomFromText(
                    'LINESTRING(
                 -104.897461 40.996484,
                 -105.021057 39.717751,
                 -104.798584 38.814031,
                 -104.48204 36.992682
             )',
                    4326
           ), ❷
         'ch13a_topology', ❸
         1 ❹
   );

Определить I-25 с помощью toTopoGeom

Геометрия; любые ребра или узлы, необходимые для формирования геометрии, будут созданы, если их нет

Топология

Слой

В листинге 7 вы добавляете топогеометрию I-25 с помощью функции toTopoGeom. Риск и преимущество использования этой функции заключается в том, что она по умолчанию создает новые ребра, узлы и грани примитивов по мере необходимости, если примитивы не существуют для формирования новой топогеометрии.

В этом примере вы уже добавили примитивные ребра в листинге 3, поэтому toTopoGeometry не должно вводить новые ребра. Вы включаете имя топологии, к которой добавляете, а также слой, с которым будет связана эта новая топогеометрия. Этот ID слоя должен быть таким же, как тот, который был возвращен при создании столбца topogeometry в листинге 5.

Если узла или ребра, необходимого для формирования новой топогеометрии, не существует, функция toTopoGeom автоматически применит допуск для поиска совпадающих узлов или ребер, прежде чем прибегать к их созданию. Другими словами, если существующий узел находится в пределах расстояния привязки геометрии линии, toTopogeom сдвинет линию, чтобы включить узел в качестве вершины вместо создания нового узла. Если вы хотите переопределить допуск по умолчанию, вы можете передать дополнительный последний аргумент в toTopogeom, чтобы применить допуск. Допуск по умолчанию, который использует toTopogeom, является функцией ограничивающей рамки входной геометрии. Этот допуск по умолчанию вычисляется внутри с помощью функции topology._ST_MinTolerance.

Чтобы подтвердить состав ваших новых топогеометрий, вы можете использовать функцию GetTopoGeomElements, как в следующем листинге.

Листинг 8. Запрос примитивных элементов автомагистралей Колорадо

SELECT highway, (topo).*, GetTopoGeomElements(topo) As el
 FROM ch13.highways_topo
 ORDER BY highway;

Этот листинг выводит четыре идентификатора подэлементов топогеометрии, доступ к которым осуществляется с помощью (topo).*), и набор топоэлементов с помощью функции GetTopoGeomElements.

highway | topology_id | layer_id | id | type |  el
 ---------+-------------+----------+----+------+-------
  I25     |           1 |        1 |  2 |    2 | {7,2}
  I25     |           1 |        1 |  2 |    2 | {8,2}
  I70     |           1 |        1 |  1 |    2 | {5,2}
  I70     |           1 |        1 |  1 |    2 | {6,2}

Код в листинге 8 возвращает набор объектов, называемых topoelements, для каждой топогеометрии. Хотя у вас есть только две строки в таблице шоссейных дорог, вы получаете четыре строки, когда используете функцию GetTopoGeomElements, потому что GetTopoGeomElements возвращает строку для каждого края каждой магистрали.

Объект Topoelement представляет собой тип домена целочисленного массива с двумя элементами: первый — это идентификатор элемента в соответствующей таблице. Поскольку ребра составляют магистрали, идентификаторы edge_ids в ch13a_topology.edge. Второй элемент топоэлемента обозначает тип слоя/класса (1 = узел, 2 = ребро, 3 = грань, а более высокие числа — это идентификаторы слоев).

Установите соглашение об именах

PostGIS не делает четкого различия между объектами базы данных, которые описывают топологические сети, и вашим собственным использованием топологий в столбцах топогеометрии. Мы советуем вам установить соглашение об именах. Множество схем и таблиц, поддерживающих топологии, может быть ошеломляющим, особенно для тех, кто занимается обслуживанием базовой сети.

Обзор использования топологий

Модель топологии PostGIS предоставляет следующие возможности для работы с топологиями:

  • Включение расширения топологии немедленно создает схему и функции топологии.
  • В таблице topology.topology записываются все топологии в вашей базе данных.
  • В таблице topology.layer записываются все столбцы (слои) топогеометрии в вашей базе данных.
  • Каждая топологическая сеть имеет свою собственную сетевую схему.
  • Примитивы (ребра, узлы, грани) имеют соответствующие таблицы в сетевой схеме.
  • Таблица отношений в конкретной сетевой схеме топологии (в данном случае ch13a_topology.relation) записывает, какие примитивы топологии и элементы слоев принадлежат к какой топогеометрии.

После того, как вы создали свои топологии, вы можете использовать их в любом месте базы данных. Вы можете использовать их где угодно в своей базе данных, построив топогеометрию из вашей топологии. Процесс следующий:

  • Добавляйте столбцы (слои) топогеометрии в собственные таблицы.
  • Создавайте топогеометрии из примитивов или других слоев и добавляйте их в свой столбец топогеометрии.
  • Добавьте топогеометрии из геометрий и измените свою базовую сеть за один шаг, используя функцию toTopoGeom. Имейте в виду, однако, что как только вы это сделаете, ребра, грани и узлы будут автоматически добавлены, а существующие разделены. Как только ваша топология изменена таким образом, простого удаления введенной топогеометрии недостаточно, чтобы вернуть изменения в топологию.

Это все для этой статьи. Если вы хотите узнать больше о книге, вы можете ознакомиться с ней в браузерной программе чтения книг Мэннинга здесь.