Быстрый старт

Данное руководство описывает действия, необходимые для открытия источника с данными и произведения с ними базовых манипуляций. Примеры, приведенные в данном руководстве можно выполнить в редакторе скриптов питона, который является частью приложения Axioma.GIS.

1. Чтение данных

1.1. Открытие источника

1.1.1. Файловый источник данных

Для открытия таблицы с данными и последующей регистрации ее в каталоге с данными необходимо выполнить следующее:

import axioma.core
json = {"src":"C:\\SubjectRF.TAB"}
table = axioma.core.open_json(json)
axioma.app.mainWindow.registerDataObject(table)

1.1.2. СУБД

При открытии таблицы из базы данных задание источника данных может выглядеть так:

json = {
        "openWith": "PgDataProvider",
        "src": "localhost",
        "port": "5432",
        "db": "esti",
        "user": "postgres",
        "password": "",
        "sql": "select * from subjectrf",
}
table = axioma.core.open_json(json)

1.2. Запрос записей

К полученному открытому источнику данных table для получения информации можно сделать запрос данных.

Для запроса всех записей в таблице используем метод allFeatures():

from axioma.core.dp import *
features = table.allFeatures()

Если необходимо ограничить количество полей указанным списком, то с методе selectToFeatureList() задаем перечень полей:

features = table.selectToFeatureList(QuerySelectAll(["object", "OBL_NAME"]))

Получение перечня атрибутов таблицы attributeNames():

print(table.tableSchema().attributeNames())

Если необходимо ограничить количество запрашиваемых записей, используем PageRange:

features = table.selectToFeatureList(QuerySelectAll(table.tableSchema().attributeNames()), PageRange(0, 10))

Это может быть полезно, если есть необходимость чтения данных порциями.

Если необходимо выполнить запрос с наложением фильтра в ограничивающем прямоугольнике, GeoRect используем метод selectFeaturesInMbr():

geoRect  = GeoRect(QRectF(33, 57, 10, 5), CoordSysFactory.defaultCoordSysFactory().LatLongCoordSystem())
features = table.selectFeaturesInMbr(geoRect)

1.3. Получение метаданных

Для определения положения атрибута с геометрией и ее оформления в структуре таблицы используем методы geometryIndex() и styleIndex():

geomIndex = table.tableSchema().geometryIndex()
styleIndex = table.tableSchema().styleIndex()

Координатную систему таблицы получаем с помощью метода и coordSystem():

from axioma.cs import *
cs = table.coordSystem()
print("КС таблицы:", cs.prjStr())

Так же метаданные по геометрическому атрибуту можно получить из схемы таблицы GeometryAttributeDefinitionInterface

geomDef = table.tableSchema().at(geomIndex)
cs = geomDef.coordSystem()
rect = geomDef.boundingRectF()

Для доступа к каждому элементу после получения списка записей можно использовать цикл:

for feature in features:
        print("id={} name={}".format(feature.id(), feature.getAttribute('OBL_NAME')))

1.4. Чтение атрибутов

Получить атрибут записи можно либо по имени либо по его индексу getAttribute(). Геометрия и ее стиль определяется аналогично:

simpleAttr = feature.getAttribute('OBL_NAME')
simpleAttr = feature.getAttribute(2)
geomAttr = feature.getAttribute(geomIndex)
geomAttr = feature.getAttribute("object")
styleAttr = feature.getAttribute(styleIndex)

Полученные стиль и геометрию для наглядности можно представить в текстовом формате:

from axioma.mapinfo import MapBasicStyle
print("Геометрия в формате WKT", geomAttr.exportToWkt())
print ("Стиль в формате строки MapBasic", MapBasicStyle().stringFromStyle(styleAttr))

2. Изменение данных

Перед проведением модификаций необходимо убедиться, что таблица поддерживает возможность изменения:

if isinstance(table, TransactionalTable):
        print('Таблица доступна для изменений')

Проведем операцию вставки новой записи. Для этого вначале создадим новую запись Feature, используя структуру (схему) открытой для изменения таблицы:

new_feature = Feature.createFeature(table.tableSchema())

Создадим геометрический объект-полигон и пометим его как измененный:

from PyQt5.QtGui import QPolygonF
from axioma.core.geometry import *

poly = QPolygonF();
poly << QPointF(50, 50) << QPointF(80, 50) << QPointF(80, 40) << QPointF(50, 40) << QPointF(50, 50)
polygon = Polygon(table.coordSystem(), poly)
new_feature.setAttribute(geomIndex, polygon)
new_feature.setModified(geomIndex, True)

Аналогично для стиля оформления:

style = MapBasicStyle().styleFromString('Pen (1,2,0) Brush (2, 65280, 16777215)')
new_feature.setAttribute(styleIndex, style)
new_feature.setModified(styleIndex, True)

И простой текстовый атрибут:

new_feature.setAttribute('OBL_NAME', 'Новый объект')
new_feature.setModified('OBL_NAME', True)

Далее сделаем вставку в транзакционную таблицу. При этом создается файл транзакций и основной файл остается неизменным.

table.insert([new_feature])

После проведения всех необходимых изменений сохраняем их в файле.

table.commit()

3. Представление данных

3.1. Вывод в растровый файл

3.1.1. Простой вывод

Отрисуем данные таблицы в растровый файл.

Для этого для начала создадим слой Layer для отрисовки на базе таблицы createLayerForDataObject():

from axioma.render import *
layer = axioma.app.render.createLayerForDataObject(table)

Задаем прямоугольник на карте для отрисовки:

br = layer.boundingRect()
sceneRect = QRectF(br.left(), br.top(), br.width(), br.height())

И прямоугольник результирующего растра:

size = QSize(1000, 1000 * br.height() / br.width())
imRect = QRect(0, 0, size.width(), size.height())

На базе этой информации создаем MapViewport:

viewport = MapViewport(QRectF(imRect), sceneRect, layer.coordSystem())

Создаем результирующий растр:

image = QImage(imRect.size(), QImage.Format_ARGB32_Premultiplied)
image.fill(Qt.white)
painter = QPainter(image)

Контекст, куда рисуем MapContext:

context = MapContext(painter, viewport)

Непосредственно отрисовка слоя в контексте:

layer.render(context)

Сохранение результатов в файловой системе:

image.save('/tmp/out_raster.png')

3.1.2. Многопоточный вывод

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

Создать объект-карту Map и заполнить его слоями:

map = Map()
map.rootLayerGroup().append(layer)
map.rootLayerGroup().append(anotherLayer)

Далее, создаем объект, занимающийся многопоточной отрисовкой ConcurrentMapRenderer и производим многопоточную отрисовку:

renderer = ConcurrentMapRenderer()
renderer.blockingRender(map, context)

3.1.3. Вывод в координатную систему, которая отличается от табличной

Если мы хотим произвести вывод в координатной системе, отличной от КС таблицы, то изменения в коде будут следующие:

Создаем требуемую координатную систему посредством фабрики CoordSysFactory:

from axioma.cs import *
cs_merc = CoordSysFactory.defaultCoordSysFactory().createFromPRJ("Earth Projection 10, 104, \"m\", 0")

Если это необходимо, производим преобразование ограничивающего прямоугольника таблицы в данную координатную систему:

transform = CoordTransform(layer.coordSystem(), cs_merc)
sceneRectMerc = transform.forward(sceneRect)

Или же задаем требуемый нам явно.

И наш MapViewport будет выглядеть так:

viewport = MapViewport(QRectF(imRect), sceneRectMerc, cs_merc)

3.2. Создание и печать отчета

Создадим простой отчет размером 2 на 2 листа формата A4 с одним геометрическим элементом. Для начала нужно создать объект принтера. Печать будем производить в pdf файл.

from PyQt5.QtPrintSupport import QPrinter
printer = QPrinter(QPrinter.HighResolution)
printer.setPaperSize(QPrinter.A4)
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName('/tmp/out_report.pdf')

Далее сам отчет Report:

from axioma.render import *
report = axioma.render.Report()
report.setHorisontalPagesCount(2)
report.setVerticalPageCount(2)
report.setOptions(printer)

Создаем контекст для вывода:

deviceRect = sceneRect = QRectF(0, 0, 100, 100)
viewport = Viewport(deviceRect, sceneRect)
context = Context(painter, viewport)

Создаем элемент отчета типа геометрия и добавляем его в отчет:

cs_ne = CoordSysFactory.defaultCoordSysFactory().createFromPRJ("CoordSys Nonearth Units \"m\"" )
poly = QPolygonF()
poly << QPointF(20, 20) << QPointF(80, 50) << QPointF(120, 20) << QPointF(320, 320) << QPointF(120, 180) << QPointF(20,  20)
geom = Polygon(cs_ne, poly)
style = MapBasicStyle().styleFromString("Pen (1, 5, 16711935) Brush (8, 255, 16777215)")
geomItem = GeometryReportItem(report)
geomItem.setGeometry(geom)
geomItem.setStyle(style)
report.addItem(geomItem)

Отрисовка:

report.render(context)
painter = None

4. Интерфейс

4.2. Добавление карты и окна просмотре информации в главном окне приложения

Откроем таблицу и добавим ее в окно карты и покажем в виде таблицы просмотра

import axioma.app
from PyQt5.QtCore import QRectF, QPointF

# Открываем таблицу
table = axioma.core.open_json({"src" : "/tmp/world.tab"})
# Если нужно, чтобы пользователь видел таблицу в списке открытых данных,
# добавляем её в каталог приложения
axioma.app.mainWindow.dataCatalog().addDataObject(table)
# Создаём слой для таблицы
layer = axioma.app.render.createLayerForDataObject(table)
# Создаём окно карты и показываем его в главном окне
mapView = axioma.app.mainWindow.createMapViewForLayerList([layer], 'Моя карта')
# Показываем таблицу в виде списка
axioma.app.mainWindow.showTableData(table)

4.2. Добавление кнопки в панель инструментов

Добавим простую кнопку в панель инструментов, по нажатию которой выводится на консоль простое сообщение.

import axioma.gui
import PyQt5.QtGui

# Объявляем свой класс расширения
class ExampleActionExtension(axioma.gui.NativeActionExtension):

# Необходимо переопределить метод customizeAction, задав параметры для создаваемого объекта QAction
    def customizeAction(self, action):
        action.setText("Пример действия")
        action.setIcon(PyQt5.QtGui.QIcon(":/icons/32px/run.png"))
        action.triggered.connect(self.slot);

# Действие по нажатию
    def slot(self):
        print('Нажали кнопку')

# Регистрация в системе на новой закладке
ribbonExt = axioma.gui.extension.RibbonExtension()
ribbonExt.addTab("ExamplePluginTab", "Пример модуля")
actionExt = ExampleActionExtension("ActionExtensionId", axioma.gui.RibbonActionInfo())
ribbonExt.addAction("ActionExtensionId", "ExamplePluginTab", "") # Добавление в интерфейс
axioma.app.gui.prependExtensions([ribbonExt, actionExt]) # Регистрация

4.3. Добавление кнопки-инструмента для работы с окном карты

Добавим кнопку - инструмент окна карты в панель инструментов. Если выбрать данный инструмент и щелкнуть мышью в окне карты, будут выведены координаты этого места в координатах текущей проекции карты.

from PyQt5.QtGui import QMouseEvent, QIcon
from PyQt5.QtCore import Qt
from axioma.gui import *

# Определяем свой класс инструмента
class ExampleTool(Tool):

    def mousePressEvent(self, event):
        if event.button() != Qt.LeftButton:
            return
        posOnMap = self.widget().viewport().mapToScene(event.pos()) # Преобразуем координаты из окна в координаты карты
        print("Координаты точки карты ({}, {})".format(posOnMap.x(), posOnMap.y())) # выводим полученную координату
        return Tool.PassEvent

# Регистрируем наш инструемнт в виде расширения в системе.
ext = axioma.gui.extension.BasicToolExtension(ExampleTool, axioma.gui.MapView, "ExampleToolId", icon=QIcon("://icons/32px/info.png"), text="Координаты точки карты")
axioma.app.gui.prependExtension(ext)

# Добавляем инструмент в закладку карты
ribbonExt = axioma.gui.extension.RibbonExtension()
ribbonExt.addAction("ExampleToolId", "map", "operations")
axioma.app.gui.prependExtension(ribbonExt)