QGIS - Tvorba zásuvného modulu krok za krokem
Stránka obsahuje poznámky pro tvorbu vlastního zásuvného modulu pro aplikaci QGIS. Navržený modul má na vstupu dvě vektorové vrstvy - bodovou a polygonovou. Na výstupu vytvoří novou vektorovou vrstvu obsahující pouze body ležící uvnitř polygonů (viz příklad pro knihovnu OGR). Uvedený text čerpá především z QGIS Coding and Compilation Guide. Zdrojové texty najdete zde.
Minimální kód
Projekt obsahuje tři soubory:
- Soubor projektu sampleplugin.pro
# cesta k adresari se zdrojovymi texty QGISu
QGIS_DIR = /opt/src/qgis_trunk
TEMPLATE = lib
CONFIG = qt
QT += xml
unix:LIBS += -L/$$QGIS_DIR/lib \
-lqgis_core \
-lqgis_gui
INCLUDEPATH += $$QGIS_DIR/src/ui \
$$QGIS_DIR/src/plugins \
$$QGIS_DIR/src/gui \
$$QGIS_DIR/src/raster \
$$QGIS_DIR/src/core \
$$QGIS_DIR
SOURCES = qgssampleplugin.cpp
HEADERS = qgssampleplugin.h
DEST = sampleplugin.so
DEFINES += GUI_EXPORT= \
CORE_EXPORT=
- Hlavičkový soubor pluginu qgssampleplugin.h
#ifndef QGSSAMPLEPLUGIN_H
#define QGSSAMPLEPLUGIN_H
#include "qgisplugin.h"
/* Testovaci plugin pro QGIS - prostorove predikaty */
class QgsSamplePlugin: public QgisPlugin
{
public:
QgsSamplePlugin(QgisInterface *);
~QgsSamplePlugin();
void initGui();
void unload();
private:
QgisInterface *mIface;
};
#endif // QGSSAMPLEPLUGIN_H
- C++ soubor qgssampleplugin.cpp
#include "qgssampleplugin.h"
#ifdef WIN32
#define QGISEXTERN extern "C" __declspec( dllexport )
#else
#define QGISEXTERN extern "C"
#endif
QgsSamplePlugin::QgsSamplePlugin(QgisInterface* iface): mIface(iface)
{
}
QgsSamplePlugin::~QgsSamplePlugin()
{
}
// Zobrazit elementy GUI nastrojove listy a menu pluginu
void QgsSamplePlugin::initGui()
{
}
// Odstranit alokovane GUI elementy
void QgsSamplePlugin::unload()
{
}
// generator pluginu
QGISEXTERN QgisPlugin* classFactory(QgisInterface* iface)
{
return new QgsSamplePlugin(iface);
}
QGISEXTERN QString name()
{
return "Within";
}
QGISEXTERN QString description()
{
return "Prostorovy predikat within";
}
QGISEXTERN QString version()
{
return "0.00001";
}
// Typ pluginu (UI nebo MapLayer plugin)
QGISEXTERN int type()
{
return QgisPlugin::UI;
}
// Odstranit plugin
QGISEXTERN void unload(QgisPlugin* theQgsSamplePluginPointer)
{
delete theQgsSamplePluginPointer;
}
Modifikujeme QgisInterface, přidáme QAction se slotem within(). Třída SamplePlugin bude odvozena z třídy QObject.
- Hlavičkový soubor pluginu qgssampleplugin.h
...
#include "qgisplugin.h"
#include <QObject>
class QAction;
/* Testovaci plugin pro QGIS - prostorove predikaty */
class QgsSamplePlugin: public QObject, public QgisPlugin
{
Q_OBJECT // nutne pro pouziti mechanismu signalu a slotu
...
private:
QgisInterface *mIface;
QAction *mAction;
private slots:
void within();
};
#endif // QGSSAMPLEPLUGIN_H
- C++ soubor qgssampleplugin.cpp
#include "qgisinterface.h"
#include "qgssampleplugin.h"
#include <QAction>
...
QgsSamplePlugin::QgsSamplePlugin(QgisInterface* iface): mIface(iface), mAction(0)
{
}
...
// Zobrazit elementy GUI nastrojove listy a menu pluginu
void QgsSamplePlugin::initGui()
{
mAction = new QAction(tr("&Within"), this);
connect(mAction, SIGNAL(activated()), this, SLOT(within()));
mIface->addToolBarIcon(mAction);
mIface->addPluginToMenu(tr("&Prostorovy predikat"), mAction);
}
// Odstranit alokovane GUI elementy
void QgsSamplePlugin::unload()
{
mIface->removeToolBarIcon(mAction);
mIface->removePluginMenu(tr("&Prostorovy predikat"), mAction);
delete mAction;
}
void QgsSamplePlugin::within()
{
}
...
Debugovací zprávy
Logovaní zajišťuje třída QgsLogger.
#include "qgslogger.h"
...
QgsLogger::debug("Layer name: " + layer1->name());
Implementace funkce within()
- C++ soubor qgssampleplugin.cpp
...
#include "qgsmapcanvas.h"
#include "qgsvectordataprovider.h"
#include "qgsfeature.h"
#include "qgsgeometry.h"
#include "qgslogger.h"
#include "qgsvectorlayer.h"
...
#include <QMessageBox>
...
void QgsSamplePlugin::within()
{
QgsMapCanvas *canvas = mIface->mapCanvas();
if(canvas->layerCount() < 2) {
QMessageBox::information(0, tr("Chyba"),
tr("Tento plugin vyzaduje alespon dve vrstvy"),
QMessageBox::Ok);
return;
}
QgsMapLayer *layer1, *layer2;
layer1 = canvas->layer(0);
layer2 = canvas->layer(1);
QgsVectorLayer* layer_points = dynamic_cast<QgsVectorLayer*>(layer1);
QgsVectorLayer* layer_polygons = dynamic_cast<QgsVectorLayer*>(layer2);
if(!layer_points || !layer_polygons) {
QMessageBox::information(0, tr("Chyba"),
tr("Tento plugin vyzaduje alespon dve vektorove vrstvy"),
QMessageBox::Ok);
return;
}
QgsVectorDataProvider *provider_points = layer_points->dataProvider();
QgsVectorDataProvider *provider_polygons = layer_polygons->dataProvider();
QgsLogger::debug("Points layer name: " + layer_points->name());
QgsLogger::debug("Polygon layer name: " + layer_polygons->name());
if (!provider_points || !provider_polygons) {
return;
}
QgsLogger::debug("Points layer provider: " + provider_points->storageType());
QgsLogger::debug("Polygon layer provider: " + provider_polygons->storageType());
layer_points->select(provider_points->attributeIndexes(), canvas->extent(), true, false);
QgsFeature feature1, feature2;
QgsGeometry *geometry1 = NULL, *geometry2 = NULL;
while(layer_points->nextFeature(feature1)) {
QgsLogger::debug("Checking feature " + QString::number(feature1.id()));
geometry1 = feature1.geometry();
if (!geometry1)
continue;
layer_polygons->select(provider_polygons->attributeIndexes(), geometry1->boundingBox(), true, true);
while(layer_polygons->nextFeature(feature2)) {
geometry2 = feature2.geometry();
if (!geometry2)
continue;
if (geometry1->within(geometry2)) {
QgsLogger::debug("WITHIN Point " + QString::number(feature1.id()) + " within polygon " + QString::number(feature2.id()));
layer_points->select(feature1.id());
}
}
}
return;
}
...

Vytvoření nové vektorové vrstvy
Vektorová vrstva je reprezentována třídou QgsVectorLayer. Nově vytvořenou vrstvu zaregistrujeme pomocí QgsMapLayerRegistry.