Расширение GIS дает возможность загружать в NetLogo данные из геоинформационных систем (ГИС), как векторные (точки, линии, полигоны), так и растровые (сетки — grids). Векторные данные поддерживаются в формате шейп-файлов ESRI (.shp) — наиболее распространенном формате хранения и обмена ГИС-данными. Растровые данные поддерживаются в форме Grid-файлов (.asc или .grd).
В Models Library, в разделе Code examples помещены два примера: GIS General Examples и GIS Gradient Example. Изучение этих примеров — самый удобный на данный момент способ изучения возможностей расширения GIS.
Все команды расширения GIS начинаются с префикса «gis:»
Как загружать геоданные
Для использования возможностей расширения GIS, его нужно подключить к NetLogo командой extensions
. Т.е. первой строкой программы должно быть
extensions [ gis ] ;; подключаем расширение gis
Затем нужно задать преобразование между пространством геоданных и игровым миром NetLogo. При этом можно указать картографическую проекцию, в которую будут преобразованы геоданные или указать используемую в них географическую систему координат.
Для указания географической системы координат используется команда gis:load-coordinate-system
; географическая СК в файле projection.prj
gis:load-coordinate-system "WGS84.prj"
; выбор ГСК с помощью переменной projection
gis:load-coordinate-system (word "data/" projection ".prj")
Команда word
осуществляет конкатенацию строк, а значение переменной projection — строка, содержащая имя файла с картографической проекцией. В результате выполнения word формируется полный путь к файлу с проекцией.
Для задания картографической проекции геоданные должны содержать файлы .prj, одноименные с шейп-файлами. Если prj-файлы существуют, то они определяют, в какой картографической проекции будут представлены геоданные. Если эти файлы отсутствует, то предполагается, что набор данных уже спроектирован как нам нужно, и преобразуется в игровой мир NetLogo «как есть».
Как только определен способ преобразования геоданных, можно загружать наборы геоданных, используя команду gis:load-dataset
:
gis:load-dataset "data/ukr_city.shp"
Эта команда возвращает или векторный или растровый набор данных, в зависимости от типа переданного ей файла.
Преобразование между пространством геоданных и игровым миром осуществляется так: берется множество «конвертов» (envelopes) (т.е. прямоугольников, образованных минимальными и максимальными значениями координат объекта или группы объектов) для всех используемых наборов данных, и отображается непосредственно в границах игрового мира NetLogo. Например, так (файл GIS_Cities_ukr0.nlogo. Все файлы примеров находятся в архиве):
extensions [ gis ] ;; подключаем расширение gis
globals [ cities-dataset ]
to setup
clear-all
; Загрузим набор геоданных
set cities-dataset gis:load-dataset "data/ukr_city.shp"
; Конверт из набора геоданных city-dataset становится "мировым"
gis:set-world-envelope (gis:envelope-of cities-dataset)
end
Пояснений заслуживает строчка
gis:set-world-envelope (gis:envelope-of cities-dataset)
Команда gis:envelope-of объект
возвращает конверт, т.е. замкнутый прямоугольник, содержащий четыре элемента: [ minimum-x maximum-x minimum-y maximum-y ]
для объекта в ГИС-координатах. Объект может быть агентом, множеством агентов, векторным или растровым набором данных или векторным объектом.
В нашем примере
gis:envelope-of cities-dataset
возвращает конверт для набора данных cities-dataset.
Команда gis:set-world-envelope
конверт определяет преобразование конверта, изображающего игровой мир NetLogo в конверт, определенный в ГИС-данных, при котором сохраняются одинаковые масштабы преобразований вдоль осей x и y. Этот примитив используется часто, поскольку обычно необходимо преобразовать игровой мир NetLogo в целом, а не какую-то из его частей.
У нас получается, что
gis:set-world-envelope <конверт координат городов>
Как узнать, что хранится в шейп-файле
Команда gis:feature-list-of НаборВекторныхДанных
возвращает список свойств для заданного набора векторных геоданных. Если к рассмотренному выше коду добавить, например, такой:
; Какие данные о городах хранятся в шейп-файле?
to display-cities
foreach gis:feature-list-of cities-dataset
[ print ? ]
end
Это даст в результате:
Команда gis:property-names ВекторныйНаборДанных
возвращает список строк — полей заданного набора геоданных. Следовательно
print gis:property-names cities-dataset
Выдаст список полей данных о городах:
[UKR_CITY_I ID NAME]
Если нас интересуют координаты городов, можно поступить так (заменяем старый код display-cities новым):
; Отмечаем города, основываясь на данных из шейп-файла
to display-cities
foreach gis:feature-list-of cities-dataset
; gis:vertex-lists-of возвращает для каждого города список списков точек,
; из которого нам нужны только два первых значения — координаты города.
; Поэтому первый first возвращает первый элемент — первый вложенный
; список, а второй first — элементы этого списка (координаты).
; Координаты храним в локальной переменной location
[ let location gis:location-of (first (first (gis:vertex-lists-of ?)))
; выводим значения координат городов, отнесенных к игровому миру
type gis:property-value ? "NAME"
type ": "
print location
]
end
Что дает
Команда gis:vertex-lists-of ВекторныйОбъект
возвращает список, состоящий из списков значений вершин. Для точечных данных, каждый список будет содержать ровно одну вершину: расположение данной точки.
gis:location-of Вершина
— возвращает список из двух элементов, содержащий координаты x и y (именно в таком порядке) заданной вершины (vertex), переведенные в соответствующие координаты игрового мира, или пустой список, если данная вершина лежит за пределами игрового мира.
gis:property-value ВекторныйОбъект ИмяПоля
— возвращает значение заданного поля указанного векторного объекта. Возвращаемая величина может быть числом, строкой или логической константой, в зависимости от типа поля в соответствующем файле данных.
В нашем примере: gis:property-value ? "NAME"
, т.е. объектом являются векторные данные о городе, а полем — "NAME" — название города.
Отображение точечных объектов
Примером точечных объектов могут служить города, попробуем изобразить расположение городов на карте мира.
extensions [ gis ]
globals [ cities-dataset ]
breed [ city-labels city-label ]
to display-cities
foreach gis:feature-list-of cities-dataset
[ let location gis:location-of (first (first (gis:vertex-lists-of ?)))
; Значение location может быть пустым списком, если данная точка
; лежит за пределами координат игрового мира. Поэтому устраиваем проверку.
if not empty? location
[ create-city-labels 1 ; создадим один элемент рода city-labels
[ set xcor item 0 location ; значения координат возьмем из location
set ycor item 1 location
set label gis:property-value ? "NAME"
; в данной точке поставим метку со значением поля "NAME"
] ] ]
end
label — встроенная переменная черепашек (связей). Может принимать значение любого типа (числовое, строковое, логическое). В результате выполнения set label
возле изображения черепашки (связи) в игровом мире возникает надпись, значение которой равно значению переменой label. Еще один пример:
ask turtles [ set label who ]
;; все черепашки помечаются своими номерами
После задания координат xcor и ycor уместно добавить строку set size 0
, чтобы отображались не сами черепашки, а только их метки. Получим в результате
Теперь отобразим в игровом мире крупнейшие города. Если население города превышает 500 тыс. человек, то город изображается желтым кружком, диаметр которого пропорционален численности населения, а название города (метка) выводится красным цветом. Если население города меньше 500 тыс. человек, то выводится только название города (белым цветом) (GIS_Cities2.nlogo).
extensions [ gis ]
globals [ cities-dataset ]
breed [ city-labels city-label ]
to setup
clear-all
set cities-dataset gis:load-dataset "data/cities.shp"
gis:set-world-envelope (gis:envelope-of cities-dataset)
end
to display-cities
foreach gis:feature-list-of cities-dataset
[ let location gis:location-of (first (first (gis:vertex-lists-of ?)))
if not empty? location
[ create-city-labels 1 ; создадим один элемент рода city-labels
[ set xcor item 0 location ; значения координат возьмем из location
set ycor item 1 location
let population gis:property-value ? "POPULATION"
ifelse (population >= 5E5)
[ set color yellow
set shape "circle"
set size 2E-7 * (gis:property-value ? "POPULATION")
set label-color red ]
[ set size 0]
; в данной точке поставим метку со значением поля "NAME"
set label gis:property-value ? "NAME"
] ] ]
end
Отображение полигонов
Рассмотрим пример (GIS_Countries0.nlogo):
extensions [ gis ]
globals [ countries-dataset ]
to setup
clear-all
set countries-dataset gis:load-dataset "data/countries.shp"
gis:set-world-envelope (gis:envelope-of countries-dataset)
end
; Рисование полигональных данных из шейп-файла
to display-countries
gis:set-drawing-color white
gis:draw countries-dataset 1
end
Существенно новым в примере является только код процедуры display-countries
. Здесь используются:
gis:set-drawing-color цвет
— устанавливает цвет, которым изображаются ГИС-объектыgis:draw ВекторныеДанные ТолщинаЛинии
— рисует указанные векторные данные линией заданной толщины и цветом, установленным для ГИС-объектов.
Возникает вопрос: а нельзя ли аналогично отображать и города? Оказывается можно. Но, если понадобится выводить названия городов, тут не обойтись без gis:vertex-lists-of
и пр.
Изобразим теперь кроме контура территории еще и название страны. Это можно сделать так:
extensions [ gis ]
globals [ countries-dataset ]
breed [ country-labels country-label ]
to startup ;; вызывается при первом запуске модели
; Загружаем геоданные
set countries-dataset gis:load-dataset "data/countries.shp"
end
to setup
clear-all-but-globals
; Задаем мировой "конверт"
gis:set-world-envelope (gis:envelope-of countries-dataset)
end
; Рисование полигональных данных из шейп-файла
to display-countries
gis:set-drawing-color white
gis:draw countries-dataset 1
foreach gis:feature-list-of countries-dataset
; находим координаты центроида, чтобы...
[ let centroid gis:location-of gis:centroid-of ? ; поставить название страны
if not empty? centroid
[ create-country-labels 1
[ set xcor item 0 centroid
set ycor item 1 centroid
set size 0
set label gis:property-value ? "CNTRY_NAME" ] ] ]
end
to clear-all-but-globals
reset-ticks ct cp cd clear-links clear-all-plots clear-output
end
Основная проблема здесь — указакть название страны в центре ее территории. Для этого используется команда gis:centroid-of ВекторныйОбъект
. Она возвращает единственную точку — центроид (центр гравитации) для данного объекта. Для точечных наборов данных координаты центроида равны средним значение x- и y-координат объекта.
В результате работы программы, получим:
Кроме того, в этом примере используются процедуры startup
и clear-all-but-globals
.
Процедура startup
вызывается автоматически при открытии файла с моделью. Это очень удобно для загрузки геоданных. Но если после этого в процедуре setup
использовать clear-all
, это очистит память и, среди прочего, сотрет загруженные геоданные (являющиеся глобальными переменными). Вместо этого используется процедура clear-all-but-globals
, которая очищает то же, что и clear-all
, за исключением глобальных переменных.
Загрузка нескольких наборов геоданных
До сих пор мы использовали наборы геоданных по одному. Если использовать несколько наборов (например, данные о городах и странах, как в примере ниже), то нужно объединить все имеющиеся у нас конверты с данными с помощью команды gis:envelope-union-of
.
to setup
clear-all
clear-output
; Загрузим наборы геоданных
set cities-dataset gis:load-dataset "data/cities.shp"
set countries-dataset gis:load-dataset "data/countries.shp"
; Мировой конверт представляет собой объединение конвертов наборов геоданных
gis:set-world-envelope (gis:envelope-union-of (gis:envelope-of cities-dataset)
(gis:envelope-of countries-dataset))
end
Отображение полилиний
Полилиниями, как правило, представляются реки и автодороги. Действуя аналогично тому, как мы это делали при отображении стран, получаем (GIS Rivers1.nlogo)
extensions [ gis ]
globals [ rivers-dataset ]
to setup
clear-all
; Загружаем геоданные
set rivers-dataset gis:load-dataset "data/rivers.shp"
; Задаем мировой "конверт"
gis:set-world-envelope (gis:envelope-of rivers-dataset)
end
; Рисуем полилинии из шейп-файла
to display-rivers
gis:set-drawing-color blue ; текущий цвет ГИС-объектов — синий
gis:draw rivers-dataset 1 ; нарисовать линией толщины 1
end
Отображаем название рек также как и для стран, используя центроид:
to display-rivers
gis:set-drawing-color blue ; текущий цвет ГИС-объектов — синий
gis:draw rivers-dataset 1 ; нарисовать линией толщины 1
foreach gis:feature-list-of rivers-dataset ; название реки отмечается на карте с помощью центроида
[ let centroid gis:location-of gis:centroid-of ?
; центроид может оказаться пустым, если он лежит за пределами
; игрового мира, определенными текущим преобразованием ГИС-координат в
; координаты игрового мира
if not empty? centroid
[ create-river-labels 1
[ set xcor item 0 centroid
set ycor item 1 centroid
set size 0 ; создается "невидимая" черепашка, зато с подписью:
set label gis:property-value ? "NAME" ] ] ]
end
Если проделать все рассмотренные операции вместе для данных о городах, областях, реках, автодорогах, то должно получиться нечто вроде:
Комментарии
comments powered by Disqus