[QGIS Commit] r9744 - docs/trunk/english_us/user_guide

svn_qgis at osgeo.org svn_qgis at osgeo.org
Fri Dec 5 11:43:44 EST 2008


Author: dassau
Date: 2008-12-05 11:43:44 -0500 (Fri, 05 Dec 2008)
New Revision: 9744

Modified:
   docs/trunk/english_us/user_guide/plugins_writing_in_cpp.tex
   docs/trunk/english_us/user_guide/plugins_writing_in_python.tex
Log:
update python plugin and added new c++ plugin with help from Marco Hugentobler. 
Needs to be reviewed and polished. 


Modified: docs/trunk/english_us/user_guide/plugins_writing_in_cpp.tex
===================================================================
--- docs/trunk/english_us/user_guide/plugins_writing_in_cpp.tex	2008-12-05 14:08:25 UTC (rev 9743)
+++ docs/trunk/english_us/user_guide/plugins_writing_in_cpp.tex	2008-12-05 16:43:44 UTC (rev 9744)
@@ -4,9 +4,788 @@
 % comment out the following line:
 \updatedisclaimer
 
-Writing plugins in C++.
+In this section we provide a beginner's tutorial for writing a simple QGIS
+C++ plugin. It is based on a workshop held by Dr. Marco Hugentobler. 
 
-\newpage
+\subsection{Why C++ and what about licensing}
 
+QGIS is written in C++ (noch ein bisschem mehr...). 
 
 
+QGIS C++ plugins use functionalities of libqgis*.so libraries. As they are
+licensed under GNU GPL, QGIS C++ plugins must be licenced under the GPL, too.
+This means you may use your plugins for any purpose and you are not forced to
+publish them. If you do publish them however, they must be published under
+the conditions of the GPL license. 
+
+\subsection{What are C++ plugins and how do they technically work}
+
+QGIS C++ plugins are dynamically linked libraries (.so or .dll). They are
+linked to QGIS at runtime when requested in the plugin manager and extend the
+functionality of QGIS. They have access to the QGIS GUI and can be devided
+into core and external plugins.
+
+Technically the QGIS plugin manager looks in the lib/qgis directory for all
+.so files and loads them when it is started. When it is closed they are
+unloaded again, except the ones with a checked box. For newly loaded plugins,
+the \method{classFactory} method creates an instance of the plugin class and
+the \method{initGui} method of the plugin is called to show the GUI elements
+in the plugin menu and toolbar. The \method{unload()} function of the plugin
+is used to remove the allocated GUI elements and the plugin class itself is
+removed using the class destructor. To list the plugins, each plugin must
+have a few external 'C' functions for description and of course the
+\method{classFactory} method.
+
+\subsection{Programming a QGIS C++ Plugin in four steps}
+
+The example plugin is a point converter plugin and intentionally kept simple. 
+The plugin searches the active vector layer in QGIS, converts all vertices of
+the layer features to point features keeping the attributes and finally
+writes the point features into a delimited text file. The new layer can then
+be loaded into QGIS using the delimited text plugin (see Section
+\ref{label_dltext}).
+
+\minisec{Step 1: Make the plugin manager recognise the plugin}
+
+As a first step we create the \filename{QgsPointConverter.h} and
+\filename{QgsPointConverter.cpp} files. Then we add virtual methods inherited
+from QgisPlugin (but leave them empty for now), create necessary external 'C'
+methods and .pro file, which is a Qt mechanism to easily create Makefiles.
+Then we compile the sources, move the compiled library into the plugin folder
+and load the new plugin in the QGIS plugin manager.
+
+\begin{verbatim}
+pointconverter.pro:
+#base directory of the qgis installation
+QGIS_DIR = /home/marco/src/qgis
+
+TEMPLATE = lib
+CONFIG = qt
+QT += xml qt3support
+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 = qgspointconverterplugin.cpp
+HEADERS = qgspointconverterplugin.h
+DEST = pointconverterplugin.so
+DEFINES += GUI_EXPORT= CORE_EXPORT=
+
+qgspointconverterplugin.h:
+
+#ifndef QGSPOINTCONVERTERPLUGIN_H
+#define QGSPOINTCONVERTERPLUGIN_H
+
+#include "qgisplugin.h"
+
+/**A plugin that converts vector layers to delimited text point files.
+ The vertices of polygon/line type layers are converted to point features*/
+class QgsPointConverterPlugin: public QgisPlugin
+{
+  public:
+  QgsPointConverterPlugin(QgisInterface* iface);
+  ~QgsPointConverterPlugin();
+  void initGui();
+  void unload();
+  
+  private:
+  QgisInterface* mIface;
+};
+#endif
+
+qgspointconverterplugin.cpp:
+
+#include "qgspointconverterplugin.h"
+
+#ifdef WIN32
+#define QGISEXTERN extern "C" __declspec( dllexport )
+#else
+#define QGISEXTERN extern "C"
+#endif
+
+QgsPointConverterPlugin::QgsPointConverterPlugin(QgisInterface* iface): mIface(iface)
+{
+}
+
+QgsPointConverterPlugin::~QgsPointConverterPlugin()
+{
+}
+
+void QgsPointConverterPlugin::initGui()
+{
+}
+
+void QgsPointConverterPlugin::unload()
+{
+}
+
+QGISEXTERN QgisPlugin* classFactory(QgisInterface* iface)
+{
+  return new QgsPointConverterPlugin(iface);
+}
+
+QGISEXTERN QString name()
+{
+  return "point converter plugin";
+}
+
+QGISEXTERN QString description()
+{
+  return "A plugin that converts vector layers to delimited text point files";
+}
+
+QGISEXTERN QString version()
+{
+  return "0.00001";
+}
+
+// Return the type (either UI or MapLayer plugin)
+QGISEXTERN int type()
+{
+  return QgisPlugin::UI;
+}
+
+// Delete ourself
+QGISEXTERN void unload(QgisPlugin* theQgsPointConverterPluginPointer)
+{
+  delete theQgsPointConverterPluginPointer;
+}
+
+\end{verbatim}
+
+\minisec{Step 2: Create an icon, a button and a menu for the plugin}
+
+This step includes adding a pointer to the QgisInterface object in the plugin
+class. Then we create a QAction and a callback function (slot), add it to the
+QGIS GUI using QgisIface::addToolBarIcon() and QgisIface::addPluginToMenu()
+and finally remove the QAction in the unload() method.
+
+\begin{verbatim}
+pointconverterplugin.h:
+
+#ifndef QGSPOINTCONVERTERPLUGIN_H
+#define QGSPOINTCONVERTERPLUGIN_H
+
+#include "qgisplugin.h"
+#include <QObject>
+
+class QAction;
+
+/**A plugin that converts vector layers to delimited text point files.
+ The vertices of polygon/line type layers are converted to point features*/
+class QgsPointConverterPlugin: public QObject, public QgisPlugin
+{
+  Q_OBJECT
+
+ public:
+  QgsPointConverterPlugin(QgisInterface* iface);
+  ~QgsPointConverterPlugin();
+  void initGui();
+  void unload();
+  
+ private:
+  QgisInterface* mIface;
+  QAction* mAction;
+  
+   private slots:
+   void convertToPoint();
+};
+
+#endif
+
+pointconverterplugin.cpp:
+
+#include "qgspointconverterplugin.h"
+#include "qgisinterface.h"
+#include <QAction>
+
+#ifdef WIN32
+#define QGISEXTERN extern "C" __declspec( dllexport )
+#else
+#define QGISEXTERN extern "C"
+#endif
+
+QgsPointConverterPlugin::QgsPointConverterPlugin(QgisInterface* iface): mIface(iface), mAction(0)
+{
+
+}
+
+QgsPointConverterPlugin::~QgsPointConverterPlugin()
+{
+
+}
+
+void QgsPointConverterPlugin::initGui()
+{
+  mAction = new QAction(tr("&Convert to point"), this);
+  connect(mAction, SIGNAL(activated()), this, SLOT(convertToPoint()));
+  mIface->addToolBarIcon(mAction);
+  mIface->addPluginToMenu(tr("&Convert to point"), mAction);
+}
+
+void QgsPointConverterPlugin::unload()
+{
+  mIface->removeToolBarIcon(mAction);
+  mIface->removePluginMenu(tr("&Convert to point"), mAction);
+  delete mAction;
+}
+
+void QgsPointConverterPlugin::convertToPoint()
+{
+  qWarning("in method convertToPoint");
+}
+
+QGISEXTERN QgisPlugin* classFactory(QgisInterface* iface)
+{
+  return new QgsPointConverterPlugin(iface);
+}
+
+QGISEXTERN QString name()
+{
+  return "point converter plugin";
+}
+
+QGISEXTERN QString description()
+{
+  return "A plugin that converts vector layers to delimited text point files";
+}
+
+QGISEXTERN QString version()
+{
+  return "0.00001";
+}
+
+// Return the type (either UI or MapLayer plugin)
+QGISEXTERN int type()
+{
+  return QgisPlugin::UI;
+}
+
+// Delete ourself
+QGISEXTERN void unload(QgisPlugin* theQgsPointConverterPluginPointer)
+{
+  delete theQgsPointConverterPluginPointer;
+}
+
+\end{verbatim}
+
+
+\minisec{Step 3: Read point features from the active layer and write to text file}
+
+To read the point features from the active layer we need to query the current
+layer and the location for the new text file. Then we iterate through all the
+features of the current layer, convert their geometries (vertices) to points,
+open a new text file and use QTextStream to write the x- and y-coordinates
+into it.
+
+\begin{verbatim}
+
+pointconverterplugin.h:
+
+additionally to the previous steps:
+
+class QgsGeometry;
+class QTextStream;
+
+private:
+
+void convertPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const;
+void convertMultiPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const;
+void convertLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const;
+void convertMultiLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const;
+void convertPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const;
+void convertMultiPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const;
+
+pointconverterplugin.cpp:
+
+additionally to the previous steps:
+
+#include "qgsgeometry.h"
+#include "qgsvectordataprovider.h"
+#include "qgsvectorlayer.h"
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QTextStream>
+
+void QgsPointConverterPlugin::convertToPoint()
+{
+  qWarning("in method convertToPoint");
+  QgsMapLayer* theMapLayer = mIface->activeLayer();
+  if(!theMapLayer)
+    {
+      QMessageBox::information(0, tr("no active layer"), tr("this plugin needs an active point vector layer to make conversions to points"), QMessageBox::Ok);
+      return;
+    }
+  QgsVectorLayer* theVectorLayer = dynamic_cast<QgsVectorLayer*>(theMapLayer);
+  if(!theVectorLayer)
+    {
+      QMessageBox::information(0, tr("no vector layer"), tr("this plugin needs an active point vector layer to make conversions to points"), QMessageBox::Ok);
+      return;
+    }
+  
+  QString fileName = QFileDialog::getSaveFileName();
+  if(!fileName.isNull())
+    {
+      qWarning("The selected filename is: " + fileName);
+      QFile f(fileName);
+      if(!f.open(QIODevice::WriteOnly))
+      {
+	QMessageBox::information(0, "error", "Could not open file", QMessageBox::Ok);
+	return;
+      }
+      QTextStream theTextStream(&f);
+      theTextStream.setRealNumberNotation(QTextStream::FixedNotation);
+
+      QgsFeature currentFeature;
+      QgsGeometry* currentGeometry = 0;
+
+      QgsVectorDataProvider* provider = theVectorLayer->dataProvider();
+      if(!provider)
+      {
+          return;
+      }
+
+      theVectorLayer->select(provider->attributeIndexes(), theVectorLayer->extent(), true, false);
+
+      //write header
+      theTextStream << "x,y";
+      theTextStream << endl;
+
+      while(theVectorLayer->nextFeature(currentFeature))
+      {
+	 QString featureAttributesString;
+      
+        currentGeometry = currentFeature.geometry();
+        if(!currentGeometry)
+        {
+            continue;
+        }
+
+        switch(currentGeometry->wkbType())
+        {
+            case QGis::WKBPoint:
+            case QGis::WKBPoint25D:
+                convertPoint(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBMultiPoint:
+            case QGis::WKBMultiPoint25D:
+                convertMultiPoint(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBLineString:
+            case QGis::WKBLineString25D:
+                convertLineString(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBMultiLineString:
+            case QGis::WKBMultiLineString25D:
+                convertMultiLineString(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBPolygon:
+            case QGis::WKBPolygon25D:
+                convertPolygon(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBMultiPolygon:
+            case QGis::WKBMultiPolygon25D:
+                convertMultiPolygon(currentGeometry, featureAttributesString, theTextStream);
+                break;
+        }
+      }
+    }
+}
+
+//geometry converter functions
+void QgsPointConverterPlugin::convertPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsPoint p = geom->asPoint();
+    stream << p.x() << "," << p.y();
+    stream << endl;
+}
+
+void QgsPointConverterPlugin::convertMultiPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsMultiPoint mp = geom->asMultiPoint();
+    QgsMultiPoint::const_iterator it = mp.constBegin();
+    for(; it != mp.constEnd(); ++it)
+    {
+        stream << (*it).x() << "," << (*it).y();
+        stream << endl;
+    }
+}
+
+void QgsPointConverterPlugin::convertLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsPolyline line = geom->asPolyline();
+    QgsPolyline::const_iterator it = line.constBegin();
+    for(; it != line.constEnd(); ++it)
+    {
+        stream << (*it).x() << "," << (*it).y();
+        stream << endl;
+    }
+}
+
+void QgsPointConverterPlugin::convertMultiLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsMultiPolyline ml = geom->asMultiPolyline();
+    QgsMultiPolyline::const_iterator lineIt = ml.constBegin();
+    for(; lineIt != ml.constEnd(); ++lineIt)
+    {
+        QgsPolyline currentPolyline = *lineIt;
+        QgsPolyline::const_iterator vertexIt = currentPolyline.constBegin();
+        for(; vertexIt != currentPolyline.constEnd(); ++vertexIt)
+        {
+            stream << (*vertexIt).x() << "," << (*vertexIt).y();
+            stream << endl;
+        }
+    }
+}
+
+void QgsPointConverterPlugin::convertPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsPolygon polygon = geom->asPolygon();
+    QgsPolygon::const_iterator it = polygon.constBegin();
+    for(; it != polygon.constEnd(); ++it)
+    {
+        QgsPolyline currentRing = *it;
+        QgsPolyline::const_iterator vertexIt = currentRing.constBegin();
+        for(; vertexIt != currentRing.constEnd(); ++vertexIt)
+        {
+            stream << (*vertexIt).x() << "," << (*vertexIt).y();
+            stream << endl;
+        }
+    }
+}
+
+void QgsPointConverterPlugin::convertMultiPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsMultiPolygon mp = geom->asMultiPolygon();
+    QgsMultiPolygon::const_iterator polyIt = mp.constBegin();
+    for(; polyIt != mp.constEnd(); ++polyIt)
+    {
+        QgsPolygon currentPolygon = *polyIt;
+        QgsPolygon::const_iterator ringIt = currentPolygon.constBegin();
+        for(; ringIt != currentPolygon.constEnd(); ++ringIt)
+        {
+            QgsPolyline currentPolyline = *ringIt;
+            QgsPolyline::const_iterator vertexIt = currentPolyline.constBegin();
+            for(; vertexIt != currentPolyline.constEnd(); ++vertexIt)
+            {
+                stream << (*vertexIt).x() << "," << (*vertexIt).y();
+                stream << endl;
+            }
+        }
+    }
+}
+
+\end{verbatim}
+
+
+
+
+\minisec{Step 4: Copy the feature attributes to the text file}
+
+At the end we extract the attributes from the active layer using
+QgsVectorDataProvider::fieldNameMap(). For each feature we extract the field
+values using QgsFeature::attributeMap() and add the contents comma separated
+behind the x- and y-coordinates for each new point feature.
+
+\begin{verbatim}
+no change for qgspointconverterplugin.h:
+
+source for qgspointconverterplugin.cpp:
+
+#include "qgspointconverterplugin.h"
+#include "qgisinterface.h"
+#include "qgsgeometry.h"
+#include "qgsvectordataprovider.h"
+#include "qgsvectorlayer.h"
+#include <QAction>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QTextStream>
+
+#ifdef WIN32
+#define QGISEXTERN extern "C" __declspec( dllexport )
+#else
+#define QGISEXTERN extern "C"
+#endif
+
+QgsPointConverterPlugin::QgsPointConverterPlugin(QgisInterface* iface): mIface(iface), mAction(0)
+{
+
+}
+
+QgsPointConverterPlugin::~QgsPointConverterPlugin()
+{
+
+}
+
+void QgsPointConverterPlugin::initGui()
+{
+  mAction = new QAction(tr("&Convert to point"), this);
+  connect(mAction, SIGNAL(activated()), this, SLOT(convertToPoint()));
+  mIface->addToolBarIcon(mAction);
+  mIface->addPluginToMenu(tr("&Convert to point"), mAction);
+}
+
+void QgsPointConverterPlugin::unload()
+{
+  mIface->removeToolBarIcon(mAction);
+  mIface->removePluginMenu(tr("&Convert to point"), mAction);
+  delete mAction;
+}
+
+void QgsPointConverterPlugin::convertToPoint()
+{
+  qWarning("in method convertToPoint");
+  QgsMapLayer* theMapLayer = mIface->activeLayer();
+  if(!theMapLayer)
+    {
+      QMessageBox::information(0, tr("no active layer"), tr("this plugin needs an active point vector layer to make conversions to points"), QMessageBox::Ok);
+      return;
+    }
+  QgsVectorLayer* theVectorLayer = dynamic_cast<QgsVectorLayer*>(theMapLayer);
+  if(!theVectorLayer)
+    {
+      QMessageBox::information(0, tr("no vector layer"), tr("this plugin needs an active point vector layer to make conversions to points"), QMessageBox::Ok);
+      return;
+    }
+  
+  QString fileName = QFileDialog::getSaveFileName();
+  if(!fileName.isNull())
+    {
+      qWarning("The selected filename is: " + fileName);
+      QFile f(fileName);
+      if(!f.open(QIODevice::WriteOnly))
+      {
+	QMessageBox::information(0, "error", "Could not open file", QMessageBox::Ok);
+	return;
+      }
+      QTextStream theTextStream(&f);
+      theTextStream.setRealNumberNotation(QTextStream::FixedNotation);
+
+      QgsFeature currentFeature;
+      QgsGeometry* currentGeometry = 0;
+
+      QgsVectorDataProvider* provider = theVectorLayer->dataProvider();
+      if(!provider)
+      {
+          return;
+      }
+
+      theVectorLayer->select(provider->attributeIndexes(), theVectorLayer->extent(), true, false);
+
+      //write header
+      theTextStream << "x,y";
+      QMap<QString, int> fieldMap = provider->fieldNameMap();
+      //We need the attributes sorted by index.
+      //Therefore we insert them in a second map where key / values are exchanged
+      QMap<int, QString> sortedFieldMap;
+      QMap<QString, int>::const_iterator fieldIt = fieldMap.constBegin();
+      for(; fieldIt != fieldMap.constEnd(); ++fieldIt)
+      {
+        sortedFieldMap.insert(fieldIt.value(), fieldIt.key());
+      }
+
+      QMap<int, QString>::const_iterator sortedFieldIt = sortedFieldMap.constBegin();
+      for(; sortedFieldIt != sortedFieldMap.constEnd(); ++sortedFieldIt)
+      {
+          theTextStream << "," << sortedFieldIt.value();
+      }
+
+      theTextStream << endl;
+
+      while(theVectorLayer->nextFeature(currentFeature))
+      {
+        QString featureAttributesString;
+         const QgsAttributeMap& map = currentFeature.attributeMap();
+         QgsAttributeMap::const_iterator attributeIt = map.constBegin();
+         for(; attributeIt != map.constEnd(); ++attributeIt)
+         {
+            featureAttributesString.append(",");
+            featureAttributesString.append(attributeIt.value().toString());
+         }
+
+
+        currentGeometry = currentFeature.geometry();
+        if(!currentGeometry)
+        {
+            continue;
+        }
+
+        switch(currentGeometry->wkbType())
+        {
+            case QGis::WKBPoint:
+            case QGis::WKBPoint25D:
+                convertPoint(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBMultiPoint:
+            case QGis::WKBMultiPoint25D:
+                convertMultiPoint(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBLineString:
+            case QGis::WKBLineString25D:
+                convertLineString(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBMultiLineString:
+            case QGis::WKBMultiLineString25D:
+                convertMultiLineString(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBPolygon:
+            case QGis::WKBPolygon25D:
+                convertPolygon(currentGeometry, featureAttributesString, theTextStream);
+                break;
+
+            case QGis::WKBMultiPolygon:
+            case QGis::WKBMultiPolygon25D:
+                convertMultiPolygon(currentGeometry, featureAttributesString, theTextStream);
+                break;
+        }
+      }
+    }
+}
+
+//geometry converter functions
+void QgsPointConverterPlugin::convertPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsPoint p = geom->asPoint();
+    stream << p.x() << "," << p.y();
+    stream << attributeString;
+    stream << endl;
+}
+
+void QgsPointConverterPlugin::convertMultiPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsMultiPoint mp = geom->asMultiPoint();
+    QgsMultiPoint::const_iterator it = mp.constBegin();
+    for(; it != mp.constEnd(); ++it)
+    {
+        stream << (*it).x() << "," << (*it).y();
+        stream << attributeString;
+        stream << endl;
+    }
+}
+
+void QgsPointConverterPlugin::convertLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsPolyline line = geom->asPolyline();
+    QgsPolyline::const_iterator it = line.constBegin();
+    for(; it != line.constEnd(); ++it)
+    {
+        stream << (*it).x() << "," << (*it).y();
+        stream << attributeString;
+        stream << endl;
+    }
+}
+
+void QgsPointConverterPlugin::convertMultiLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsMultiPolyline ml = geom->asMultiPolyline();
+    QgsMultiPolyline::const_iterator lineIt = ml.constBegin();
+    for(; lineIt != ml.constEnd(); ++lineIt)
+    {
+        QgsPolyline currentPolyline = *lineIt;
+        QgsPolyline::const_iterator vertexIt = currentPolyline.constBegin();
+        for(; vertexIt != currentPolyline.constEnd(); ++vertexIt)
+        {
+            stream << (*vertexIt).x() << "," << (*vertexIt).y();
+            stream << attributeString;
+            stream << endl;
+        }
+    }
+}
+
+void QgsPointConverterPlugin::convertPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsPolygon polygon = geom->asPolygon();
+    QgsPolygon::const_iterator it = polygon.constBegin();
+    for(; it != polygon.constEnd(); ++it)
+    {
+        QgsPolyline currentRing = *it;
+        QgsPolyline::const_iterator vertexIt = currentRing.constBegin();
+        for(; vertexIt != currentRing.constEnd(); ++vertexIt)
+        {
+            stream << (*vertexIt).x() << "," << (*vertexIt).y();
+            stream << attributeString;
+            stream << endl;
+        }
+    }
+}
+
+void QgsPointConverterPlugin::convertMultiPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
+{
+    QgsMultiPolygon mp = geom->asMultiPolygon();
+    QgsMultiPolygon::const_iterator polyIt = mp.constBegin();
+    for(; polyIt != mp.constEnd(); ++polyIt)
+    {
+        QgsPolygon currentPolygon = *polyIt;
+        QgsPolygon::const_iterator ringIt = currentPolygon.constBegin();
+        for(; ringIt != currentPolygon.constEnd(); ++ringIt)
+        {
+            QgsPolyline currentPolyline = *ringIt;
+            QgsPolyline::const_iterator vertexIt = currentPolyline.constBegin();
+            for(; vertexIt != currentPolyline.constEnd(); ++vertexIt)
+            {
+                stream << (*vertexIt).x() << "," << (*vertexIt).y();
+                stream << attributeString;
+                stream << endl;
+            }
+        }
+    }
+}
+
+QGISEXTERN QgisPlugin* classFactory(QgisInterface* iface)
+{
+  return new QgsPointConverterPlugin(iface);
+}
+
+QGISEXTERN QString name()
+{
+  return "point converter plugin";
+}
+
+QGISEXTERN QString description()
+{
+  return "A plugin that converts vector layers to delimited text point files";
+}
+
+QGISEXTERN QString version()
+{
+  return "0.00001";
+}
+
+// Return the type (either UI or MapLayer plugin)
+QGISEXTERN int type()
+{
+  return QgisPlugin::UI;
+}
+
+// Delete ourself
+QGISEXTERN void unload(QgisPlugin* theQgsPointConverterPluginPointer)
+{
+  delete theQgsPointConverterPluginPointer;
+}
+
+\end{verbatim}
+
+\subsection{Further information}
+
+As you can see, you need information from different sources to write QGIS C++
+plugins. Plugin writers need to know C++, the QGIS plugin interface as
+well as Qt4 classes and tools. At the beginning it is best to learn from
+examples and copy the mechanism of existing plugins. 
+
+There is a a collection of online documentation that may be usefull for
+QGIS C++ programers:
+
+\begin{itemize}
+\item QGIS Plugin Debugging: \url{http://wiki.qgis.org/qgiswiki/DebuggingPlugins}
+\item QGIS API Documentation: \url{http://svn.qgis.org/api_doc/html/}
+\item Qt documentation: \url{http://doc.trolltech.com/4.3/index.html}
+\end{itemize}
+

Modified: docs/trunk/english_us/user_guide/plugins_writing_in_python.tex
===================================================================
--- docs/trunk/english_us/user_guide/plugins_writing_in_python.tex	2008-12-05 14:08:25 UTC (rev 9743)
+++ docs/trunk/english_us/user_guide/plugins_writing_in_python.tex	2008-12-05 16:43:44 UTC (rev 9744)
@@ -27,9 +27,7 @@
 both are licensed under GNU GPL, QGIS Python plugins must be licenced under the
 GPL, too. This means you may use your plugins for any purpose and you are not
 forced to publish them. If you do publish them however, they must be
-published under the conditions of the GPL license. With Python programs, this
-restriction is not as important as for compiled programs, because the source
-code is visible anyway.
+published under the conditions of the GPL license. 
 
 \subsection{What needs to be installed to get started}
 



More information about the QGIS-commit mailing list