QGIS / Tvorba zásuvného modulu

Z FreeGIS portál
Přejít na: navigace, hledání

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;
}

Ikonka, tlačítko a menu pluginu

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;
}
...
Demonstrace pluginu

Vytvoření nové vektorové vrstvy

Vektorová vrstva je reprezentována třídou QgsVectorLayer. Nově vytvořenou vrstvu zaregistrujeme pomocí QgsMapLayerRegistry. Vlastnosti vrstvy při vykreslení definuje třída QgsSingleSymbolRenderer.

Externí odkazy