\section{C++ Anwendungen erstellen}

Nicht jeder wünscht sich eine "'aufgeblähte"' Desktop-GIS-Anwendung. 
Zuweilen ist auch eine Vorrichtung in der Anwendung gewünscht, welche einfach nur
die Karte darstellt, während das eigentliche Ziel, 
die eigentliche Anwendung ganz woanders liegt. Wie wäre es z.B. mit einer
Datenbank-Anwendung mit Kartendarstellung? Dieses 
Kapitel erläutert zwei Code-Beispiele von Tim Sutton welche im QGIS Subversion
Repository liegen (neben vielen anderen interessanten Beispielen). 
Das gesamte Repository können Sie hier auschecken:
\filename{https://svn.osgeo.org/qgis/trunk/code\_examples/}

\subsection{Eine einfache Kartendarstellung erstellen}\label{subsec:simple_widget}

Mit dieser ersten Anleitung werden wir eine einfache Kartendarstellung erstellen.
Die Anwendung wird begrenzt sein, es wird lediglich ein einfaches Shapefile geladen 
und in einer Zufallsfarbe visualisiert.
Das Beispiel wird aber einen Eindruck vermitteln wie QGIS als integrierte Kartenkomponente
funktioniert. An dieser Stelle zunächst einmal vielen Dank an Francis Bolduc, 
welcher den Anfang dieses Tutoriums erstellt hat.
Zunächst einmal beginnen wir mit den typischen Includings für unsere Anwendung:

\begin{verbatim}
//
// QGIS Includes
//
#include <qgsapplication.h>
#include <qgsproviderregistry.h>
#include <qgssinglesymbolrenderer.h>
#include <qgsmaplayerregistry.h>
#include <qgsvectorlayer.h>
#include <qgsmapcanvas.h>
//
// Qt Includes
//
#include <QString>
#include <QApplication>
#include <QWidget>
\end{verbatim}

Wir gebrauchen an dieser Stelle "'QgsApplication"' anstelle von "'Qt's
QApplication"' und erhalten dadurch zusätzlichen Nutzen durch verschiedene
Methoden welche z.B. unterschiedliche Pfade von Bibliotheken lokalisieren.

Die "'providerregistry"' sorgt dafür, dass Plugins für Vektor-Daten hinzugefügt 
werden. Die Basis-Symbol-Klasse wird durch den "'singlesymbolrenderer"'
dargestellt. Hierdurch werden Punkte, Linien und Polygone in einer Zufallsfarbe präsentiert.
Jeder Vektor-Layer muss letztlich über eine bestimmte Symbologie verfügen.
"'Maplayerregistry"' ist zuständig für die verwendeten Layer.
Diese Vektor-Layer-Klasse erbt von "'maplayer"' und sorgt für verschiedene erweiterte
Vektor-Daten-Funktionalitäten.
Last but not least sorgt "apcanvas" für das eigentliche Zeichnen der Karte.

Weiter geht es mit der Initialisierung der Anwendung \dots

\begin{verbatim}
int main(int argc, char ** argv)
{
  // Start der Anwendung
  QgsApplication app(argc, argv, true);

  QString myPluginsDir        = "/home/timlinux/apps/lib/qgis";
  QString myLayerPath         = "/home/timlinux/gisdata/brazil/BR_Cidades/";
  QString myLayerBaseName     = "Brasil_Cap";
  QString myProviderName      = "ogr";
\end{verbatim}

Wir haben nun also eine Quantum GIS Anwendung mit einigen Variablen.
In diesem Falle liegen die Plugin in einem Entwicklungs-Installations-Verzeichnis.
Natürlich können diese auch in einem Standard-Bibliotheken-Verzeichnis liegen wie 
z.B.: /usr/lib.

Die nächsten beiden Variablen gehören zu dem hier verwendeten Shapefile (Sie sollten hier 
entsprechende Einträge ändern).
Der ProviderName ist wichtig - 
hier wird angegeben welche Bibliothek verwendet wird um die Datei zu laden.

Anschließend geht es nun darum ein erstes Layer-Objekt zu schaffen:

\begin{verbatim}
  QgsProviderRegistry::instance(myPluginsDir);
\end{verbatim}

Zunächst geht es darum die "'ProviderRegistry"' zu initialisieren.
Wir nutzen hierfür den statischen Instance-Aufruf und übergeben diesen an den
Suchpfad von "'myPluginsDir"'.
Während der Initialisierung wird das entsprechende Verzeichnis nach den
provider-Bibliotheken untersucht.

\begin{verbatim}
  QgsVectorLayer * mypLayer =
      new QgsVectorLayer(myLayerPath, myLayerBaseName, myProviderName);
  QgsSingleSymbolRenderer *mypRenderer = new
QgsSingleSymbolRenderer(mypLayer->geometryType());
  QList <QgsMapCanvasLayer> myLayerSet;

  mypLayer->setRenderer(mypRenderer);
  if (mypLayer->isValid())
  {
    qDebug("Layer is valid");
  }
  else
  {
    qDebug("Layer is NOT valid");
  }

  // Hinzufügen des Layers zur "LayerRegistry"
  QgsMapLayerRegistry::instance()->addMapLayer(mypLayer, TRUE);
  // Hinzufügen des Layers zum Layer Set
  myLayerSet.append(QgsMapCanvasLayer(mypLayer, TRUE));
\end{verbatim}

Dieser Code erklärt sich fast von selber. Wir kreieren einen Layer indem wir die zuvor 
definierten Variablen nutzen. Dann weisen wir den Layer einem Renderer zu.
Bei der Erstellung des Renderes müssen wir den Geometrie-Typus angeben, was dadurch geschieht,
dass der Typus des Vektor-Layers abgefragt wird.
Anschließend wird der Layer einem Layerset (das Layerset wird von
"'QgsMapCanvas"' genutzt um herauszufinden, welche Layer gerendert werden
sollen bzw. in welcher Reihenfolge) sowie der "'maplayerregistry"'
hinzugefügt. Schlußendlich wird der Layer sichtbar gemacht.

Nachfolgend wird der Layer gezeichnet:

\begin{verbatim}
  // Generierung der Kartenoberfläche
  QgsMapCanvas * mypMapCanvas = new QgsMapCanvas(0, 0);
  mypMapCanvas->setExtent(mypLayer->extent());
  mypMapCanvas->enableAntiAliasing(true);
  mypMapCanvas->setCanvasColor(QColor(255, 255, 255));
  mypMapCanvas->freeze(false);
  // Generierung des Layer-Sets
  mypMapCanvas->setLayerSet(myLayerSet);
  mypMapCanvas->setVisible(true);
  mypMapCanvas->refresh();

\end{verbatim}

Auch dieser Code ist nicht besonders kompliziert.
Wir schaffen die Oberfläche und setzen diese auf die räumliche Ausdehnung der Layer.
Zudem setzen wir fest, dass die Vektordaten "'antialiased"' (also mit geringem
"'Treppcheneffekt"') gezeichnet werden. Als nächstes wird die Hintergrundfarbe
angegeben, die Sichtbarkeit gesetzt und das ganze "'refreshed"'.

\begin{verbatim}
  // Start der Anwendungsschleife
  return app.exec();
}

\end{verbatim}

Im letzten Schritt wird einfach die Qt-Schleife gestartet und das wars.
Das Beispiel kann ausgecheckt, kompiliert und mittels cmake behandelt werden wie folgt:

\begin{verbatim}
svn co
https://svn.osgeo.org/qgis/trunk/code_examples/1_hello_world_qgis_style
cd 1_hello_world_qgis_style
mkdir build
# Optional kann festgelegt werden wo Ihr QGIS installiert ist.
# Wenn Ihr QGIS in /usr oder /usr/local installiert ist können Sie den 
# nachfolgenden Schritt auslassen.
export LIB_DIR=/home/timlinux/apps
cmake ..
make
./timtut1
\end{verbatim}

Wenn das ganze kompiliert und gelaufen ist sieht es aus wie folgt:

\begin{figure}[ht]
   \begin{center}
   \caption{Einfache C++ Applikation \osxcaption}\label{fig:cpp1_application}\smallskip
   \includegraphics[clip=true]{cpp1_application}
\end{center}
\end{figure}

\subsection{Arbeiten mit QgsMapCanvas}

Im Bereich~\ref{subsec:simple_widget} wurde die Nutzung der "'QgsMapCanvas
api"' verdeutlicht um eine ganz einfache Anwendung zu erstellen, welche ein Shapefile
lädt und dessen Punkte darstellt. Aber wofür soll eine Karte nützlich sein,
wenn man damit nicht interagieren kann?

Das nachfolgende 2.Tutorium soll nun die Erstellung einer Anwendung mit Menü, Toolbar und Kartenoberfläche
verdeutlichen. Es wird gezeigt wie das "'QgsMapTool"' genutzt werden kann
- die Basisklasse für alle Werkzeuge, welche mit "'MapCanvas"' interagieren.

Sinn und Zweck ist es ein kleines Demonstrationsprojekt zu erstellen, daher
mag es sein, dass der C++-Code nicht immer der eleganteste ist.

Das Projekt wird vier Toolbar-icons beinhalten um

\begin{itemize}
 \item einen Layer zu laden
 \item ein Hineinzoomen zu gestatten
 \item ein Herauszoomen zu gestatten
 \item Panning zu gewährleisten
\end{itemize}

Im Arbeitsverzeichnis des Tutorium-Codes finden Sie eine Anzahl von Dateien 
(C++-Code, Bilder, Datenfile). Zudem befindet sich dort das .ui-File für das Hauptfenster.

\textbf{Bemerkung:} Sie werden das .pro-File editieren müssen (im svn directory)
um es an Ihr System anzupassen.

Da sehr viel Code dem vorhergegangenen Tutorium gleicht soll der Fokus hier nun
auf die MapTool-Besonderheiten gerichtet werden.
"'QgsMapTool"' ist eine Klasse welche mit MapCanvas zusammenarbeitet. QGIS
hat zahlreiche QgsMapTools implementiert. Es ist möglich eine Unterklasse
von QgsMapTools anzulegen um ein eigenes Tool zu kreieren.
In "'mainwindow.cpp"' wird verdeutlicht, dass Header für die "'QgsMapTools"'
am Anfang des Files eigebunden werden.

\begin{verbatim}
     //
     // QGIS Map tools
     //
     #include "qgsmaptoolpan.h"
     #include "qgsmaptoolzoom.h"
     //
     // Es existieren weitere header für verschiedene Tools
     // (hier nicht genutzt)
     //
     //#include "qgsmaptoolcapture.h"
     //#include "qgsmaptoolidentify.h"
     //#include "qgsmaptoolselect.h"
     //#include "qgsmaptoolvertexedit.h"
     //#include "qgsmeasure.h"
\end{verbatim}

Wie zu sehen ist werden zwei Typen von MapTool-Unterklassen fur diese Anwendung genutzt.
Weitere sind verfügbar in der QGIS-Bibliothek.
Die Tools können auf die Oberfläche gebracht werden durch Nutzung des
"'Qt4 signal/slot"'-Mechanismus:

\begin{verbatim}
     //Aktionsweisen werden generiert
     connect(mActionPan, SIGNAL(triggered()), this, SLOT(panMode()));
     connect(mActionZoomIn, SIGNAL(triggered()), this, SLOT(zoomInMode()));
     connect(mActionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOutMode()));
     connect(mActionAddLayer, SIGNAL(triggered()), this, SLOT(addLayer()));
\end{verbatim}

Als nächstes wird eine einfache Toolbar für die Buttons generiert.

\begin{verbatim}
     //Toolbar wird erstellt
     mpMapToolBar = addToolBar(tr("File"));
     mpMapToolBar->addAction(mpActionAddLayer);
     mpMapToolBar->addAction(mpActionZoomIn);
     mpMapToolBar->addAction(mpActionZoomOut);
     mpMapToolBar->addAction(mpActionPan);
\end{verbatim}

Anschließend werden unsere 3 Maptools generiert.

\begin{verbatim}
     //Generierung der Maptools
     mpPanTool = new QgsMapToolPan(mpMapCanvas);
     mpPanTool->setAction(mpActionPan);
     mpZoomInTool = new QgsMapToolZoom(mpMapCanvas, FALSE); // false = in
     mpZoomInTool->setAction(mpActionZoomIn);
     mpZoomOutTool = new QgsMapToolZoom(mpMapCanvas, TRUE ); //true = out
     mpZoomOutTool->setAction(mpActionZoomOut);
\end{verbatim}

Letztlich auch nicht besonders kompliziert. Es werden Instanzen der Tools geschaffen,
jede davon ist mit dem selben "'MapCanvas"' und einer unterschiedlichen
"'QAction"' verbunden. Wenn der User ein Toolbar-Icon wählt wird das
entsprechende Maptool gewählt. Zum Beispiel wenn das Panning-icon geklickt
ist geschieht das folgende: 

\begin{verbatim}
    void MainWindow::panMode()
    {
       mpMapCanvas->setMapTool(mpPanTool); 
    }
\end{verbatim}

\begin{figure}[ht]
   \begin{center}
   \caption{QMainWindow Applikation mit Menü, Werkzeugleiste und
Kartenfenster \osxcaption}\label{fig:cpp2_application}\smallskip
   \includegraphics[clip=true, width=\textwidth]{cpp2_application}
\end{center}
\end{figure}

\minisec{Ergebnis}

Wie man sehen kann ist der Ausbau des vorherigen Beispiels durch einige Funktionen
unter Nutzung der MapTools relativ einfach und benötigt nur wenige Zeilen
für jedes MapTool.

Das Tutorium kann ausgecheckt und kompiliert werden unter Nutzung von SVN und CMake:

\begin{verbatim}
svn co https://svn.osgeo.org/qgis/trunk/code_examples/2_basic_main_window
cd 2_basic_main_window
mkdir build
# Optional kann festgelegt werden wo Ihr QGIS installiert ist.
# Wenn Ihr QGIS in /usr oder /usr/local installiert ist können Sie den 
# nachfolgenden Schritt auslassen.
export LIB_DIR=/home/timlinux/apps
cmake ..
make
./timtut2
\end{verbatim}



