Skip to content
Permalink
Browse files

Added option to engine configuration to show candidate labels for eve…

…ry feature (as frames).

Added a simple tool that shows candidate's cost on click (in a tooltip).


git-svn-id: http://svn.osgeo.org/qgis/branches/symbology-ng-branch@11019 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
wonder
wonder committed Jul 4, 2009
1 parent cc51226 commit 0a6dfa1be0b636379e66269e450097c03ded96f9
@@ -18,6 +18,8 @@ EngineConfigDialog::EngineConfigDialog(PalLabeling* lbl, QWidget* parent)
spinCandPoint->setValue(candPoint);
spinCandLine->setValue(candLine);
spinCandPolygon->setValue(candPolygon);

chkShowCandidates->setChecked( mLBL->isShowingCandidates() );
}


@@ -30,5 +32,7 @@ void EngineConfigDialog::onOK()
spinCandLine->value(),
spinCandPolygon->value());

mLBL->setShowingCandidates( chkShowCandidates->isChecked() );

accept();
}
@@ -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>
@@ -158,6 +172,13 @@
</property>
</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">
@@ -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>
@@ -65,13 +65,46 @@ Labeling::~Labeling()
{
}

/////////

#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 @@ void Labeling::initGui()
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::run()
}
}


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

@@ -32,6 +32,7 @@ class QToolBar;
class QgisInterface;

class PalLabeling;
class LabelingTool;

class Labeling: public QObject, public QgisPlugin
{
@@ -58,14 +59,20 @@ class Labeling: public QObject, public QgisPlugin
//! 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
@@ -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 @@ void LayerSettings::registerFeature(QgsFeature& f)

// -------------

PalLabeling::PalLabeling(QgsMapCanvas* mapCanvas)
: mMapCanvas(mapCanvas), mPal(NULL)
PalLabeling::PalLabeling(QgsMapRenderer* mapRenderer)
: mMapRenderer(mapRenderer), mPal(NULL)
{

// find out engine defaults
@@ -121,8 +125,11 @@ PalLabeling::PalLabeling(QgsMapCanvas* mapCanvas)
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 @@ int PalLabeling::prepareLayerHook(void* context, void* layerContext, int& attrIn
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 @@ void PalLabeling::initPal()
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::initPal()



void PalLabeling::doLabeling(QPainter* painter)
void PalLabeling::doLabeling(QPainter* painter, QgsRectangle extent)
{

QTime t;
@@ -274,25 +282,70 @@ void PalLabeling::doLabeling(QPainter* painter)

// 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 )
{
std::cerr << "PAL EXCEPTION :-( " << e.what() << std::endl;
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 @@ void PalLabeling::doLabeling(QPainter* painter)

std::cout << "LABELING draw: " << t.elapsed() << "ms" << std::endl;

delete problem;
delete labels;

// delete all allocated geometries for features

0 comments on commit 0a6dfa1

Please sign in to comment.
You can’t perform that action at this time.