[QGIS Commit] r11019 - branches/symbology-ng-branch/src/plugins/labeling

svn_qgis at osgeo.org svn_qgis at osgeo.org
Sat Jul 4 09:35:37 EDT 2009


Author: wonder
Date: 2009-07-04 09:35:36 -0400 (Sat, 04 Jul 2009)
New Revision: 11019

Modified:
   branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.cpp
   branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.ui
   branches/symbology-ng-branch/src/plugins/labeling/labeling.cpp
   branches/symbology-ng-branch/src/plugins/labeling/labeling.h
   branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp
   branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h
Log:
Added option to engine configuration to show candidate labels for every feature (as frames).
Added a simple tool that shows candidate's cost on click (in a tooltip).


Modified: branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.cpp
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.cpp	2009-07-04 13:25:43 UTC (rev 11018)
+++ branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.cpp	2009-07-04 13:35:36 UTC (rev 11019)
@@ -18,6 +18,8 @@
   spinCandPoint->setValue(candPoint);
   spinCandLine->setValue(candLine);
   spinCandPolygon->setValue(candPolygon);
+
+  chkShowCandidates->setChecked( mLBL->isShowingCandidates() );
 }
 
 
@@ -30,5 +32,7 @@
                                  spinCandLine->value(),
                                  spinCandPolygon->value());
 
+  mLBL->setShowingCandidates( chkShowCandidates->isChecked() );
+
   accept();
 }

Modified: branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.ui
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.ui	2009-07-04 13:25:43 UTC (rev 11018)
+++ branches/symbology-ng-branch/src/plugins/labeling/engineconfigdialog.ui	2009-07-04 13:35:36 UTC (rev 11019)
@@ -27,7 +27,7 @@
       <widget class="QComboBox" name="cboSearchMethod">
        <item>
         <property name="text">
-         <string>Chain (fastest)</string>
+         <string>Chain (fast)</string>
         </property>
        </item>
        <item>
@@ -45,6 +45,11 @@
          <string>Popmusic Tabu Chain</string>
         </property>
        </item>
+       <item>
+        <property name="text">
+         <string>FALP (fastest)</string>
+        </property>
+       </item>
       </widget>
      </item>
     </layout>
@@ -88,6 +93,9 @@
           <property name="minimum">
            <number>1</number>
           </property>
+          <property name="maximum">
+           <number>999</number>
+          </property>
          </widget>
         </item>
         <item row="1" column="0">
@@ -105,6 +113,9 @@
           <property name="minimum">
            <number>1</number>
           </property>
+          <property name="maximum">
+           <number>999</number>
+          </property>
          </widget>
         </item>
         <item row="2" column="0">
@@ -122,6 +133,9 @@
           <property name="minimum">
            <number>1</number>
           </property>
+          <property name="maximum">
+           <number>999</number>
+          </property>
          </widget>
         </item>
        </layout>
@@ -159,6 +173,13 @@
     </spacer>
    </item>
    <item>
+    <widget class="QCheckBox" name="chkShowCandidates">
+     <property name="text">
+      <string>Show label candidates (for debugging)</string>
+     </property>
+    </widget>
+   </item>
+   <item>
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
@@ -170,6 +191,14 @@
    </item>
   </layout>
  </widget>
+ <tabstops>
+  <tabstop>cboSearchMethod</tabstop>
+  <tabstop>spinCandPoint</tabstop>
+  <tabstop>spinCandLine</tabstop>
+  <tabstop>spinCandPolygon</tabstop>
+  <tabstop>chkShowCandidates</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
  <resources/>
  <connections>
   <connection>

Modified: branches/symbology-ng-branch/src/plugins/labeling/labeling.cpp
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/labeling.cpp	2009-07-04 13:25:43 UTC (rev 11018)
+++ branches/symbology-ng-branch/src/plugins/labeling/labeling.cpp	2009-07-04 13:35:36 UTC (rev 11019)
@@ -65,13 +65,46 @@
 {
 }
 
+/////////
+
+#include <qgsmaptool.h>
+#include <QMouseEvent>
+#include <QToolTip>
+
+class LabelingTool : public QgsMapTool
+{
+public:
+  LabelingTool(PalLabeling* lbl, QgsMapCanvas* canvas) : QgsMapTool(canvas), mLBL(lbl) {}
+
+  virtual void canvasPressEvent( QMouseEvent * e )
+  {
+    const QList<LabelCandidate>& cand = mLBL->candidates();
+    QPointF pt = e->posF();
+    for (int i = 0; i < cand.count(); i++)
+    {
+      const LabelCandidate& c = cand[i];
+      if (c.rect.contains(pt))
+      {
+        QToolTip::showText( mCanvas->mapToGlobal(e->pos()), QString::number(c.cost), mCanvas);
+        break;
+      }
+    }
+  }
+
+protected:
+  PalLabeling* mLBL;
+};
+
+///////////
+
+
 /*
  * Initialize the GUI interface for the plugin - this is only called once when the plugin is
  * added to the plugin registry in the QGIS application.
  */
 void Labeling::initGui()
 {
-  mLBL = new PalLabeling(mQGisIface->mapCanvas());
+  mLBL = new PalLabeling(mQGisIface->mapCanvas()->mapRenderer());
 
   // Create the action for tool
   mQActionPointer = new QAction( QIcon( ":/labeling/labeling.png" ), tr( "Labeling" ), this );
@@ -83,13 +116,19 @@
   mQGisIface->addToolBarIcon( mQActionPointer );
   mQGisIface->addPluginToMenu( tr( "&Labeling" ), mQActionPointer );
 
+  mActionTool = new QAction( "Ltool", this );
+  mQGisIface->addToolBarIcon( mActionTool );
+  connect( mActionTool, SIGNAL( triggered() ), this, SLOT( setTool() ) );
+
+  mTool = new LabelingTool(mLBL, mQGisIface->mapCanvas());
+
   connect( mQGisIface->mapCanvas(), SIGNAL( renderComplete( QPainter * ) ), this, SLOT( doLabeling( QPainter * ) ) );
 
 }
 
 void Labeling::doLabeling( QPainter * painter )
 {
-  mLBL->doLabeling(painter);
+  mLBL->doLabeling(painter, mQGisIface->mapCanvas()->extent());
 }
 
 // Slot called when the menu item is triggered
@@ -119,14 +158,26 @@
   }
 }
 
+
+void Labeling::setTool()
+{
+  mQGisIface->mapCanvas()->setMapTool(mTool);
+}
+
 // Unload the plugin by cleaning up the GUI
 void Labeling::unload()
 {
+  mQGisIface->mapCanvas()->unsetMapTool(mTool);
+  delete mTool;
+
   // remove the GUI
   mQGisIface->removePluginMenu( "&Labeling", mQActionPointer );
   mQGisIface->removeToolBarIcon( mQActionPointer );
   delete mQActionPointer;
 
+  mQGisIface->removeToolBarIcon( mActionTool );
+  delete mActionTool;
+
   delete mLBL;
 }
 

Modified: branches/symbology-ng-branch/src/plugins/labeling/labeling.h
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/labeling.h	2009-07-04 13:25:43 UTC (rev 11018)
+++ branches/symbology-ng-branch/src/plugins/labeling/labeling.h	2009-07-04 13:35:36 UTC (rev 11019)
@@ -32,6 +32,7 @@
 class QgisInterface;
 
 class PalLabeling;
+class LabelingTool;
 
 class Labeling: public QObject, public QgisPlugin
 {
@@ -58,14 +59,20 @@
     //! hook to renderComplete signal
     void doLabeling(QPainter* painter);
 
+    //! start labeling map tool
+    void setTool();
+
   private:
 
     //! Pointer to the QGIS interface object
     QgisInterface *mQGisIface;
     //! Pointer to the qaction for this plugin
     QAction * mQActionPointer;
+    QAction * mActionTool;
 
     PalLabeling* mLBL;
+
+    LabelingTool* mTool;
 };
 
 #endif //Labeling_H

Modified: branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp	2009-07-04 13:25:43 UTC (rev 11018)
+++ branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp	2009-07-04 13:35:36 UTC (rev 11019)
@@ -7,6 +7,8 @@
 #include <pal/layer.h>
 #include <pal/palgeometry.h>
 #include <pal/palexception.h>
+#include <pal/problem.h>
+#include <pal/labelposition.h>
 
 #include <geos_c.h>
 
@@ -15,12 +17,14 @@
 #include <QByteArray>
 #include <QString>
 #include <QFontMetrics>
+#include <QTime>
+#include <QPainter>
 
 #include <qgsvectorlayer.h>
 #include <qgsmaplayerregistry.h>
 #include <qgsvectordataprovider.h>
 #include <qgsgeometry.h>
-#include <qgsmapcanvas.h>
+#include <qgsmaprenderer.h>
 
 using namespace pal;
 
@@ -105,8 +109,8 @@
 
 // -------------
 
-PalLabeling::PalLabeling(QgsMapCanvas* mapCanvas)
-  : mMapCanvas(mapCanvas), mPal(NULL)
+PalLabeling::PalLabeling(QgsMapRenderer* mapRenderer)
+  : mMapRenderer(mapRenderer), mPal(NULL)
 {
 
   // find out engine defaults
@@ -121,8 +125,11 @@
     case POPMUSIC_TABU: mSearch = Popmusic_Tabu; break;
     case POPMUSIC_CHAIN: mSearch = Popmusic_Chain; break;
     case POPMUSIC_TABU_CHAIN: mSearch = Popmusic_Tabu_Chain; break;
+    case FALP: mSearch = Falp; break;
   }
 
+  mShowingCandidates = FALSE;
+
   initPal();
 }
 
@@ -217,7 +224,7 @@
   lyr->fieldIndex = fldIndex;
   lyr->fontMetrics = new QFontMetrics(lyr->textFont);
   lyr->fontBaseline = lyr->fontMetrics->boundingRect("X").bottom(); // dummy text to find out how many pixels of the text are below the baseline
-  lyr->xform = thisClass->mMapCanvas->mapRenderer()->coordinateTransform();
+  lyr->xform = thisClass->mMapRenderer->coordinateTransform();
   lyr->ptZero = lyr->xform->toMapCoordinates( 0,0 );
 
   return 1; // init successful
@@ -245,6 +252,7 @@
     case Popmusic_Tabu: s = POPMUSIC_TABU; break;
     case Popmusic_Chain: s = POPMUSIC_CHAIN; break;
     case Popmusic_Tabu_Chain: s = POPMUSIC_TABU_CHAIN; break;
+    case Falp: s = FALP; break;
   }
   mPal->setSearch(s);
   //mPal->setSearch(FALP);
@@ -257,7 +265,7 @@
 
 
 
-void PalLabeling::doLabeling(QPainter* painter)
+void PalLabeling::doLabeling(QPainter* painter, QgsRectangle extent)
 {
 
   QTime t;
@@ -274,13 +282,23 @@
 
   // do the labeling itself
   double scale = 1; // scale denominator
-  QgsRectangle r = mMapCanvas->extent();
+  QgsRectangle r = extent;
   double bbox[] = { r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum() };
 
   std::list<Label*>* labels;
+  pal::Problem* problem;
   try
   {
-     labels = mPal->labeller(scale, bbox, NULL, false);
+     //labels = mPal->labeller(scale, bbox, NULL, false);
+    problem = mPal->extractProblem(scale, bbox);
+    if ( problem )
+    {
+      // TODO: other methods
+      problem->chain_search();
+      labels = problem->getSolution(false);
+    }
+    else
+      labels = new std::list<Label*>();
   }
   catch ( std::exception& e )
   {
@@ -288,11 +306,46 @@
     return;
   }
 
+  const QgsMapToPixel* xform = mMapRenderer->coordinateTransform();
+
+  // draw rectangles with all candidates
+  // this is done before actual solution of the problem
+  // before number of candidates gets reduced
+  mCandidates.clear();
+  if (mShowingCandidates && problem)
+  {
+    painter->setPen(QColor(0,0,0,64));
+    painter->setBrush(Qt::NoBrush);
+    for (int i = 0; i < problem->getNumFeatures(); i++)
+    {
+      for (int j = 0; j < problem->getFeatureCandidateCount(i); j++)
+      {
+        pal::LabelPosition* lp = problem->getFeatureCandidate(i, j);
+
+        QgsPoint outPt = xform->transform(lp->getX(), lp->getY());
+        QgsPoint outPt2 = xform->transform(lp->getX()+lp->getWidth(), lp->getY()+lp->getHeight());
+
+        painter->save();
+        painter->translate( QPointF(outPt.x(), outPt.y()) );
+        painter->rotate(-lp->getAlpha() * 180 / M_PI );
+        QRectF rect(0,0, outPt2.x()-outPt.x(), outPt2.y()-outPt.y());
+        painter->drawRect(rect);
+        painter->restore();
+
+        // save the rect
+        rect.moveTo(outPt.x(),outPt.y());
+        mCandidates.append( LabelCandidate(rect, lp->getCost() * 1000) );
+      }
+    }
+  }
+
+  // find the solution
+  labels = mPal->solveProblem( problem );
+
   std::cout << "LABELING work:   " << t.elapsed() << "ms  ... labels# " << labels->size() << std::endl;
   t.restart();
 
   // draw the labels
-  const QgsMapToPixel* xform = mMapCanvas->mapRenderer()->coordinateTransform();
   std::list<Label*>::iterator it = labels->begin();
   for ( ; it != labels->end(); ++it)
   {
@@ -317,6 +370,7 @@
 
   std::cout << "LABELING draw:   " << t.elapsed() << "ms" << std::endl;
 
+  delete problem;
   delete labels;
 
   // delete all allocated geometries for features

Modified: branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h	2009-07-04 13:25:43 UTC (rev 11018)
+++ branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h	2009-07-04 13:35:36 UTC (rev 11019)
@@ -2,12 +2,14 @@
 #define PALLABELING_H
 
 class QPainter;
-class QgsMapCanvas;
+class QgsMapRenderer;
+class QgsRectangle;
 
 #include <QString>
 #include <QFont>
 #include <QColor>
 #include <QList>
+#include <QRectF>
 
 namespace pal
 {
@@ -62,13 +64,22 @@
   QList<MyLabel*> geometries;
 };
 
+class LabelCandidate
+{
+public:
+  LabelCandidate(QRectF r, double c): rect(r), cost(c) {}
+
+  QRectF rect;
+  double cost;
+};
+
 class PalLabeling
 {
 public:
-    PalLabeling(QgsMapCanvas* mapCanvas);
+    PalLabeling(QgsMapRenderer* renderer);
     ~PalLabeling();
 
-    void doLabeling(QPainter* painter);
+    void doLabeling(QPainter* painter, QgsRectangle extent);
 
     void addLayer(LayerSettings layerSettings);
 
@@ -79,11 +90,14 @@
     void numCandidatePositions(int& candPoint, int& candLine, int& candPolygon);
     void setNumCandidatePositions(int candPoint, int candLine, int candPolygon);
 
-    enum Search { Chain, Popmusic_Tabu, Popmusic_Chain, Popmusic_Tabu_Chain };
+    enum Search { Chain, Popmusic_Tabu, Popmusic_Chain, Popmusic_Tabu_Chain, Falp };
 
     void setSearchMethod(Search s);
     Search searchMethod() const;
 
+    bool isShowingCandidates() const { return mShowingCandidates; }
+    void setShowingCandidates(bool showing) { mShowingCandidates = showing; }
+    const QList<LabelCandidate>& candidates() { return mCandidates; }
 
     //! hook called when drawing layer before issuing select()
     static int prepareLayerHook(void* context, void* layerContext, int& attrIndex);
@@ -96,11 +110,15 @@
 
 protected:
     QList<LayerSettings> mLayers;
-    QgsMapCanvas* mMapCanvas;
+    QgsMapRenderer* mMapRenderer;
     int mCandPoint, mCandLine, mCandPolygon;
     Search mSearch;
 
     pal::Pal* mPal;
+
+    // list of candidates from last labeling
+    QList<LabelCandidate> mCandidates;
+    bool mShowingCandidates;
 };
 
 #endif // PALLABELING_H



More information about the QGIS-commit mailing list