[QGIS Commit] r14697 - in trunk/qgis: images images/themes/default
python/core src/app src/core src/core/pal src/ui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Wed Nov 17 10:01:15 EST 2010
Author: mhugent
Date: 2010-11-17 07:01:15 -0800 (Wed, 17 Nov 2010)
New Revision: 14697
Added:
trunk/qgis/images/themes/default/mActionChangeLabelProperties.png
trunk/qgis/images/themes/default/mActionMoveLabel.png
trunk/qgis/images/themes/default/mActionRotateLabel.png
trunk/qgis/src/app/qgsmaptoolchangelabelproperties.cpp
trunk/qgis/src/app/qgsmaptoolchangelabelproperties.h
trunk/qgis/src/app/qgsmaptoollabel.cpp
trunk/qgis/src/app/qgsmaptoollabel.h
trunk/qgis/src/app/qgsmaptoolmovelabel.cpp
trunk/qgis/src/app/qgsmaptoolmovelabel.h
trunk/qgis/src/app/qgsmaptoolrotatelabel.cpp
trunk/qgis/src/app/qgsmaptoolrotatelabel.h
trunk/qgis/src/core/qgslabelsearchtree.cpp
trunk/qgis/src/core/qgslabelsearchtree.h
trunk/qgis/src/ui/qgslabelpropertydialogbase.ui
Modified:
trunk/qgis/images/images.qrc
trunk/qgis/python/core/qgsmaprenderer.sip
trunk/qgis/python/core/qgspoint.sip
trunk/qgis/src/app/CMakeLists.txt
trunk/qgis/src/app/qgisapp.cpp
trunk/qgis/src/app/qgisapp.h
trunk/qgis/src/app/qgspointrotationitem.cpp
trunk/qgis/src/app/qgspointrotationitem.h
trunk/qgis/src/core/CMakeLists.txt
trunk/qgis/src/core/pal/labelposition.cpp
trunk/qgis/src/core/pal/labelposition.h
trunk/qgis/src/core/qgsmaprenderer.h
trunk/qgis/src/core/qgspallabeling.cpp
trunk/qgis/src/core/qgspallabeling.h
trunk/qgis/src/core/qgspoint.cpp
trunk/qgis/src/core/qgspoint.h
Log:
[FEATURE]: move/rotate/change label edit tools to interactively change data defined label properties
Modified: trunk/qgis/images/images.qrc
===================================================================
--- trunk/qgis/images/images.qrc 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/images/images.qrc 2010-11-17 15:01:15 UTC (rev 14697)
@@ -123,6 +123,7 @@
<file>themes/default/mActionCaptureLine.png</file>
<file>themes/default/mActionCapturePoint.png</file>
<file>themes/default/mActionCapturePolygon.png</file>
+ <file>themes/default/mActionChangeLabelProperties.png</file>
<file>themes/default/mActionCheckQgisVersion.png</file>
<file>themes/default/mActionCollapseTree.png</file>
<file>themes/default/mActionComposerManager.png</file>
@@ -168,6 +169,7 @@
<file>themes/default/mActionMergeFeatures.png</file>
<file>themes/default/mActionMergeFeatureAttributes.png</file>
<file>themes/default/mActionMoveFeature.png</file>
+ <file>themes/default/mActionMoveLabel.png</file>
<file>themes/default/mActionMoveItemContent.png</file>
<file>themes/default/mActionMoveItemsToBottom.png</file>
<file>themes/default/mActionMoveItemsToTop.png</file>
@@ -191,6 +193,7 @@
<file>themes/default/mActionRemoveLayer.png</file>
<file>themes/default/mActionRemoveSelectedFeature.png</file>
<file>themes/default/mActionReshape.png</file>
+ <file>themes/default/mActionRotateLabel.png</file>
<file>themes/default/mActionRotatePointSymbols.png</file>
<file>themes/default/mActionSaveAsPDF.png</file>
<file>themes/default/mActionSaveAsSVG.png</file>
Added: trunk/qgis/images/themes/default/mActionChangeLabelProperties.png
===================================================================
(Binary files differ)
Property changes on: trunk/qgis/images/themes/default/mActionChangeLabelProperties.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/qgis/images/themes/default/mActionMoveLabel.png
===================================================================
(Binary files differ)
Property changes on: trunk/qgis/images/themes/default/mActionMoveLabel.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/qgis/images/themes/default/mActionRotateLabel.png
===================================================================
(Binary files differ)
Property changes on: trunk/qgis/images/themes/default/mActionRotateLabel.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Modified: trunk/qgis/python/core/qgsmaprenderer.sip
===================================================================
--- trunk/qgis/python/core/qgsmaprenderer.sip 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/python/core/qgsmaprenderer.sip 2010-11-17 15:01:15 UTC (rev 14697)
@@ -25,12 +25,33 @@
virtual void drawLabeling( QgsRenderContext& context ) = 0;
//! called when we're done with rendering
virtual void exit() = 0;
+ //! return infos about labels at a given (map) position
+ //! @note: this method was added in version 1.7
+ virtual QList<QgsLabelPosition> labelsAtPosition( const QgsPoint& p )= 0;
+
//! called when passing engine among map renderers
virtual QgsLabelingEngineInterface* clone() = 0;
};
+struct QgsLabelPosition
+{
+%TypeHeaderCode
+#include <qgsmaprenderer.h>
+%End
+ QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, bool upside_down );
+ QgsLabelPosition();
+ int featureId;
+ double rotation;
+ QVector< QgsPoint > cornerPoints;
+ QgsRectangle labelRect;
+ double width;
+ double height;
+ QString layerID;
+ bool upsideDown;
+};
+
/**
* \class QgsMapRenderer
* \brief Class for rendering map layer set
Modified: trunk/qgis/python/core/qgspoint.sip
===================================================================
--- trunk/qgis/python/core/qgspoint.sip 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/python/core/qgspoint.sip 2010-11-17 15:01:15 UTC (rev 14697)
@@ -77,6 +77,10 @@
@note added in QGIS 1.5*/
double sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint /Out/) const;
+ /**Calculates azimut between this point and other one (clockwise in degree, starting from north)
+ @note: this function has been added in version 1.7*/
+ double azimuth( const QgsPoint& other );
+
//! equality operator
bool operator==(const QgsPoint &other);
Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/app/CMakeLists.txt 2010-11-17 15:01:15 UTC (rev 14697)
@@ -28,6 +28,7 @@
qgsidentifyresults.cpp
qgsfeatureaction.cpp
qgslabeldialog.cpp
+ qgslabelpropertydialog.cpp
qgslabelengineconfigdialog.cpp
qgslabelinggui.cpp
qgslabelpreview.cpp
@@ -37,17 +38,21 @@
qgsmaptooladdring.cpp
qgsmaptoolannotation.cpp
qgsmaptoolcapture.cpp
+ qgsmaptoolchangelabelproperties.cpp
qgsmaptooldeletering.cpp
qgsmaptooldeletepart.cpp
qgsmaptooldeletevertex.cpp
qgsmaptooledit.cpp
qgsmaptoolformannotation.cpp
qgsmaptoolidentify.cpp
+ qgsmaptoollabel.cpp
qgsmaptoolmeasureangle.cpp
qgsmaptoolmovefeature.cpp
+ qgsmaptoolmovelabel.cpp
qgsmaptoolmovevertex.cpp
qgsmaptoolnodetool.cpp
qgsmaptoolreshape.cpp
+ qgsmaptoolrotatelabel.cpp
qgsmaptoolrotatepointsymbols.cpp
qgsmaptoolselect.cpp
qgsmaptoolselectrectangle.cpp
@@ -175,6 +180,7 @@
qgsidentifyresults.h
qgsfeatureaction.h
qgslabeldialog.h
+ qgslabelpropertydialog.h
qgsmanageconnectionsdialog.h
qgsmaptoolidentify.h
qgsmaptoolsplitfeatures.h
Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/app/qgisapp.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -212,6 +212,9 @@
#include "qgsmaptoolzoom.h"
#include "qgsmaptoolsimplify.h"
#include "qgsmeasuretool.h"
+#include "qgsmaptoolmovelabel.h"
+#include "qgsmaptoolrotatelabel.h"
+#include "qgsmaptoolchangelabelproperties.h"
//
// Conditional Includes
@@ -580,6 +583,8 @@
delete mMapTools.mDeletePart;
delete mMapTools.mAddIsland;
delete mMapTools.mNodeTool;
+ delete mMapTools.mMoveLabel;
+ delete mMapTools.mChangeLabelProperties;
delete mPythonUtils;
@@ -1229,6 +1234,18 @@
mActionAbout->setMenuRole( QAction::AboutRole ); // put in application menu on Mac OS X
connect( mActionAbout, SIGNAL( triggered() ), this, SLOT( about() ) );
+ mActionMoveLabel = new QAction( getThemeIcon( "mActionMoveLabel.png" ), tr( "Move Label" ), this );
+ mActionMoveLabel->setStatusTip( tr( "Move labels interactively" ) );
+ connect( mActionMoveLabel, SIGNAL( triggered() ), this, SLOT( moveLabel() ) );
+
+ mActionRotateLabel = new QAction( getThemeIcon( "mActionRotateLabel.png" ), tr( "Rotate Label" ), this );
+ mActionRotateLabel->setStatusTip( tr( "Rotate labels interactively" ) );
+ connect( mActionRotateLabel, SIGNAL( triggered() ), this, SLOT( rotateLabel() ) );
+
+ mActionChangeLabelProperties = new QAction( getThemeIcon( "mActionChangeLabelProperties.png" ), tr( "Change label" ), this );
+ mActionChangeLabelProperties->setStatusTip( tr( "Change label properties" ) );
+ connect( mActionChangeLabelProperties, SIGNAL( triggered() ), this, SLOT( changeLabelProperties() ) );
+
mActionStyleManagerV2 = new QAction( tr( "Style manager..." ), this );
shortcuts->registerAction( mActionStyleManagerV2 );
mActionStyleManagerV2->setStatusTip( tr( "Show style manager V2" ) );
@@ -1349,6 +1366,12 @@
mMapToolGroup->addAction( mActionNodeTool );
mActionRotatePointSymbols->setCheckable( true );
mMapToolGroup->addAction( mActionRotatePointSymbols );
+ mActionMoveLabel->setCheckable( true );
+ mMapToolGroup->addAction( mActionMoveLabel );
+ mActionRotateLabel->setCheckable( true );
+ mMapToolGroup->addAction( mActionRotateLabel );
+ mActionChangeLabelProperties->setCheckable( true );
+ mMapToolGroup->addAction( mActionChangeLabelProperties );
}
void QgisApp::createMenus()
@@ -1606,7 +1629,7 @@
// don't add it yet, wait for a plugin
mDatabaseMenu = new QMenu( tr( "&Database" ) );
-
+
// Raster Menu
mRasterMenu = menuBar()->addMenu( tr( "&Raster" ) );
@@ -1843,6 +1866,15 @@
mHelpToolBar->addAction( mActionHelpContents );
mHelpToolBar->addAction( QWhatsThis::createAction() );
mToolbarMenu->addAction( mHelpToolBar->toggleViewAction() );
+
+ //Label Toolbar
+ mLabelToolBar = addToolBar( tr( "Label" ) );
+ mLabelToolBar->setIconSize( myIconSize );
+ mLabelToolBar->setObjectName( "Label" );
+ mLabelToolBar->addAction( mActionMoveLabel );
+ mLabelToolBar->addAction( mActionRotateLabel );
+ mLabelToolBar->addAction( mActionChangeLabelProperties );
+ mToolbarMenu->addAction( mLabelToolBar->toggleViewAction() );
}
void QgisApp::createStatusBar()
@@ -2245,6 +2277,12 @@
mMapTools.mNodeTool->setAction( mActionNodeTool );
mMapTools.mRotatePointSymbolsTool = new QgsMapToolRotatePointSymbols( mMapCanvas );
mMapTools.mRotatePointSymbolsTool->setAction( mActionRotatePointSymbols );
+ mMapTools.mMoveLabel = new QgsMapToolMoveLabel( mMapCanvas );
+ mMapTools.mMoveLabel->setAction( mActionMoveLabel );
+ mMapTools.mRotateLabel = new QgsMapToolRotateLabel( mMapCanvas );
+ mMapTools.mRotateLabel->setAction( mActionRotateLabel );
+ mMapTools.mChangeLabelProperties = new QgsMapToolChangeLabelProperties( mMapCanvas );
+ mMapTools.mChangeLabelProperties->setAction( mActionChangeLabelProperties );
//ensure that non edit tool is initialised or we will get crashes in some situations
mNonEditMapTool = mMapTools.mPan;
}
@@ -4250,6 +4288,21 @@
return true;
}
+void QgisApp::moveLabel()
+{
+ mMapCanvas->setMapTool( mMapTools.mMoveLabel );
+}
+
+void QgisApp::rotateLabel()
+{
+ mMapCanvas->setMapTool( mMapTools.mRotateLabel );
+}
+
+void QgisApp::changeLabelProperties()
+{
+ mMapCanvas->setMapTool( mMapTools.mChangeLabelProperties );
+}
+
QList<QgsAnnotationItem*> QgisApp::annotationItems()
{
QList<QgsAnnotationItem*> itemList;
Modified: trunk/qgis/src/app/qgisapp.h
===================================================================
--- trunk/qgis/src/app/qgisapp.h 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/app/qgisapp.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -757,6 +757,13 @@
bool loadAnnotationItemsFromProject( const QDomDocument& doc );
+ //! Activates the move label tool
+ void moveLabel();
+ //! Activates rotate label tool
+ void rotateLabel();
+ //! Activates label property tool
+ void changeLabelProperties();
+
signals:
/** emitted when a key is pressed and we want non widget sublasses to be able
to pick up on this (e.g. maplayer) */
@@ -866,6 +873,7 @@
QToolBar *mAttributesToolBar;
QToolBar *mPluginToolBar;
QToolBar *mHelpToolBar;
+ QToolBar *mLabelToolBar;
// actions for menus and toolbars -----------------
@@ -1002,6 +1010,10 @@
QAction *mActionHelpSeparator2;
QAction *mActionAbout;
+ QAction *mActionMoveLabel;
+ QAction *mActionRotateLabel;
+ QAction *mActionChangeLabelProperties;
+
QAction *mActionUseRendererV2;
QAction *mActionStyleManagerV2;
@@ -1069,6 +1081,9 @@
QgsMapTool* mAnnotation;
QgsMapTool* mFormAnnotation;
QgsMapTool* mTextAnnotation;
+ QgsMapTool* mMoveLabel;
+ QgsMapTool* mRotateLabel;
+ QgsMapTool* mChangeLabelProperties;
} mMapTools;
QgsMapTool *mNonEditMapTool;
Added: trunk/qgis/src/app/qgsmaptoolchangelabelproperties.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolchangelabelproperties.cpp (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolchangelabelproperties.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,76 @@
+/***************************************************************************
+ qgsmaptoolchangelabelproperties.cpp
+ ---------------------------------
+ begin : 2010-11-11
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "qgsmaptoolchangelabelproperties.h"
+#include "qgslabelpropertydialog.h"
+#include "qgsmapcanvas.h"
+#include "qgsrubberband.h"
+#include "qgsvectorlayer.h"
+
+QgsMapToolChangeLabelProperties::QgsMapToolChangeLabelProperties( QgsMapCanvas* canvas ): QgsMapToolLabel( canvas )
+{
+}
+
+QgsMapToolChangeLabelProperties::~QgsMapToolChangeLabelProperties()
+{
+}
+
+void QgsMapToolChangeLabelProperties::canvasPressEvent( QMouseEvent * e )
+{
+ deleteRubberBands();
+
+ if ( !labelAtPosition( e, mCurrentLabelPos ) )
+ {
+ return;
+ }
+
+ QgsVectorLayer* vlayer = currentLayer();
+ if ( !vlayer || !vlayer->isEditable() )
+ {
+ return;
+ }
+
+ createRubberBands();
+}
+
+void QgsMapToolChangeLabelProperties::canvasReleaseEvent( QMouseEvent * e )
+{
+ QgsVectorLayer* vlayer = currentLayer();
+ if ( mLabelRubberBand && mCanvas && vlayer )
+ {
+ QgsLabelPropertyDialog d( mCurrentLabelPos.layerID, mCurrentLabelPos.featureId, mCanvas->mapRenderer() );
+ if ( d.exec() == QDialog::Accepted )
+ {
+ const QgsAttributeMap& changes = d.changedProperties();
+ if ( changes.size() > 0 )
+ {
+ vlayer->beginEditCommand( tr( "Label properties changed" ) );
+
+ QgsAttributeMap::const_iterator changeIt = changes.constBegin();
+ for ( ; changeIt != changes.constEnd(); ++changeIt )
+ {
+ vlayer->changeAttributeValue( mCurrentLabelPos.featureId, changeIt.key(), changeIt.value(), false );
+ }
+
+ vlayer->endEditCommand();
+ mCanvas->refresh();
+ }
+ }
+ deleteRubberBands();
+ }
+}
+
Added: trunk/qgis/src/app/qgsmaptoolchangelabelproperties.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoolchangelabelproperties.h (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolchangelabelproperties.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,34 @@
+/***************************************************************************
+ qgsmaptoolchangelabelproperties.h
+ ---------------------------------
+ begin : 2010-11-11
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QGSMAPTOOLCHANGELABELPROPERTIES_H
+#define QGSMAPTOOLCHANGELABELPROPERTIES_H
+
+#include "qgsmaptoollabel.h"
+
+class QgsMapToolChangeLabelProperties: public QgsMapToolLabel
+{
+ public:
+ QgsMapToolChangeLabelProperties( QgsMapCanvas* canvas );
+ ~QgsMapToolChangeLabelProperties();
+
+ virtual void canvasPressEvent( QMouseEvent * e );
+ virtual void canvasReleaseEvent( QMouseEvent * e );
+
+};
+
+#endif // QGSMAPTOOLCHANGELABEL_H
Added: trunk/qgis/src/app/qgsmaptoollabel.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoollabel.cpp (rev 0)
+++ trunk/qgis/src/app/qgsmaptoollabel.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,347 @@
+/***************************************************************************
+ qgsmaptoollabel.cpp
+ --------------------
+ begin : 2010-11-03
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "qgsmaptoollabel.h"
+#include "qgsmapcanvas.h"
+#include "qgsmaplayerregistry.h"
+#include "qgsrubberband.h"
+#include "qgsvectorlayer.h"
+#include <QMouseEvent>
+
+QgsMapToolLabel::QgsMapToolLabel( QgsMapCanvas* canvas ): QgsMapTool( canvas ), mLabelRubberBand( 0 ), mFeatureRubberBand( 0 ), mFixPointRubberBand( 0 )
+{
+}
+
+QgsMapToolLabel::~QgsMapToolLabel()
+{
+ delete mLabelRubberBand;
+ delete mFeatureRubberBand;
+ delete mFixPointRubberBand;
+}
+
+bool QgsMapToolLabel::labelAtPosition( QMouseEvent* e, QgsLabelPosition& p )
+{
+ QgsPoint pt = toMapCoordinates( e->pos() );
+ QgsLabelingEngineInterface* labelingEngine = mCanvas->mapRenderer()->labelingEngine();
+ if ( labelingEngine )
+ {
+ QList<QgsLabelPosition> labelPosList = labelingEngine->labelsAtPosition( pt );
+ QList<QgsLabelPosition>::const_iterator posIt = labelPosList.constBegin();
+ if ( posIt != labelPosList.constEnd() )
+ {
+ p = *posIt;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QgsMapToolLabel::createRubberBands( )
+{
+ delete mLabelRubberBand;
+ delete mFeatureRubberBand;
+
+ //label rubber band
+ QgsRectangle rect = mCurrentLabelPos.labelRect;
+ mLabelRubberBand = new QgsRubberBand( mCanvas, false );
+ mLabelRubberBand->addPoint( QgsPoint( rect.xMinimum(), rect.yMinimum() ) );
+ mLabelRubberBand->addPoint( QgsPoint( rect.xMinimum(), rect.yMaximum() ) );
+ mLabelRubberBand->addPoint( QgsPoint( rect.xMaximum(), rect.yMaximum() ) );
+ mLabelRubberBand->addPoint( QgsPoint( rect.xMaximum(), rect.yMinimum() ) );
+ mLabelRubberBand->addPoint( QgsPoint( rect.xMinimum(), rect.yMinimum() ) );
+ mLabelRubberBand->setColor( Qt::green );
+ mLabelRubberBand->setWidth( 3 );
+ mLabelRubberBand->show();
+
+ //feature rubber band
+ QgsVectorLayer* vlayer = currentLayer();
+ if ( vlayer )
+ {
+ QgsFeature f;
+ if ( currentFeature( f, true ) )
+ {
+ QgsGeometry* geom = f.geometry();
+ if ( geom )
+ {
+ mFeatureRubberBand = new QgsRubberBand( mCanvas, geom->type() == QGis::Polygon );
+ mFeatureRubberBand->setColor( Qt::red );
+ mFeatureRubberBand->setToGeometry( geom, vlayer );
+ mFeatureRubberBand->show();
+ }
+ }
+
+ //fixpoint rubber band
+ QgsPoint fixPoint;
+ if ( rotationPoint( fixPoint ) )
+ {
+ QgsGeometry* pointGeom = QgsGeometry::fromPoint( fixPoint );
+ mFixPointRubberBand = new QgsRubberBand( mCanvas, false );
+ mFixPointRubberBand->setColor( Qt::blue );
+ mFixPointRubberBand->setToGeometry( pointGeom, vlayer );
+ mFixPointRubberBand->show();
+ delete pointGeom;
+ }
+ }
+}
+
+void QgsMapToolLabel::deleteRubberBands()
+{
+ delete mLabelRubberBand; mLabelRubberBand = 0;
+ delete mFeatureRubberBand; mFeatureRubberBand = 0;
+ delete mFixPointRubberBand; mFixPointRubberBand = 0;
+}
+
+QgsVectorLayer* QgsMapToolLabel::currentLayer()
+{
+ QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID ) );
+ return vlayer;
+}
+
+QgsPalLayerSettings& QgsMapToolLabel::currentLabelSettings( bool* ok )
+{
+ QgsVectorLayer* vlayer = currentLayer();
+ if ( vlayer )
+ {
+ QgsPalLabeling* labelEngine = dynamic_cast<QgsPalLabeling*>( mCanvas->mapRenderer()->labelingEngine() );
+ if ( labelEngine )
+ {
+ if ( ok )
+ {
+ *ok = true;
+ }
+ return labelEngine->layer( mCurrentLabelPos.layerID );
+ }
+ }
+
+ if ( ok )
+ {
+ *ok = false;
+ }
+ return mInvalidLabelSettings;
+}
+
+QString QgsMapToolLabel::currentLabelText()
+{
+ QgsVectorLayer* vlayer = currentLayer();
+ if ( !vlayer )
+ {
+ return "";
+ }
+
+ QString labelField = vlayer->customProperty( "labeling/fieldName" ).toString();
+ if ( !labelField.isEmpty() )
+ {
+ int labelFieldId = vlayer->fieldNameIndex( labelField );
+ QgsFeature f;
+ if ( vlayer->featureAtId( mCurrentLabelPos.featureId, f, false, true ) )
+ {
+ return f.attributeMap()[labelFieldId].toString();
+ }
+ }
+ return "";
+}
+
+void QgsMapToolLabel::currentAlignment( QString& hali, QString& vali )
+{
+ hali = "Left";
+ vali = "Bottom";
+
+ QgsFeature f;
+ if ( !currentFeature( f ) )
+ {
+ return;
+ }
+ const QgsAttributeMap& featureAttributes = f.attributeMap();
+
+ bool settingsOk;
+ QgsPalLayerSettings& labelSettings = currentLabelSettings( &settingsOk );
+ if ( settingsOk )
+ {
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int > ddProperties = labelSettings.dataDefinedProperties;
+
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator haliIter = ddProperties.find( QgsPalLayerSettings::Hali );
+ if ( haliIter != ddProperties.constEnd() )
+ {
+ hali = featureAttributes[*haliIter].toString();
+ }
+
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator valiIter = ddProperties.find( QgsPalLayerSettings::Vali );
+ if ( valiIter != ddProperties.constEnd() )
+ {
+ vali = featureAttributes[*valiIter].toString();
+ }
+ }
+}
+
+bool QgsMapToolLabel::currentFeature( QgsFeature& f, bool fetchGeom )
+{
+ QgsVectorLayer* vlayer = currentLayer();
+ if ( !vlayer )
+ {
+ return false;
+ }
+ return vlayer->featureAtId( mCurrentLabelPos.featureId, f, fetchGeom, true );
+}
+
+QFont QgsMapToolLabel::labelFontCurrentFeature()
+{
+ QFont font;
+ QgsVectorLayer* vlayer = currentLayer();
+
+ bool labelSettingsOk;
+ QgsPalLayerSettings& layerSettings = currentLabelSettings( &labelSettingsOk );
+
+ if ( labelSettingsOk && vlayer )
+ {
+ font = layerSettings.textFont;
+
+ QgsFeature f;
+ if ( vlayer->featureAtId( mCurrentLabelPos.featureId, f, false, true ) )
+ {
+ const QgsAttributeMap& attributes = f.attributeMap();
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int > ddProperties = layerSettings.dataDefinedProperties;
+
+ //size
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator sizeIt = ddProperties.find( QgsPalLayerSettings::Size );
+ if ( sizeIt != ddProperties.constEnd() )
+ {
+ font.setPointSizeF( attributes[*sizeIt].toDouble() );
+ }
+
+ //family
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator familyIt = ddProperties.find( QgsPalLayerSettings::Family );
+ if ( familyIt != ddProperties.constEnd() )
+ {
+ font.setFamily( attributes[*sizeIt].toString() );
+ }
+
+ //underline
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator underlineIt = ddProperties.find( QgsPalLayerSettings::Underline );
+ if ( familyIt != ddProperties.constEnd() )
+ {
+ font.setUnderline( attributes[*underlineIt].toBool() );
+ }
+
+ //strikeout
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator strikeoutIt = ddProperties.find( QgsPalLayerSettings::Strikeout );
+ if ( strikeoutIt != ddProperties.constEnd() )
+ {
+ font.setStrikeOut( attributes[*strikeoutIt].toBool() );
+ }
+
+ //bold
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator boldIt = ddProperties.find( QgsPalLayerSettings::Bold );
+ if ( boldIt != ddProperties.constEnd() )
+ {
+ font.setBold( attributes[*boldIt].toBool() );
+ }
+
+ //italic
+ QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator italicIt = ddProperties.find( QgsPalLayerSettings::Italic );
+ if ( italicIt != ddProperties.constEnd() )
+ {
+ font.setItalic( attributes[*italicIt].toBool() );
+ }
+ }
+ }
+
+ return font;
+}
+
+bool QgsMapToolLabel::rotationPoint( QgsPoint& pos )
+{
+ QVector<QgsPoint> cornerPoints = mCurrentLabelPos.cornerPoints;
+ if ( cornerPoints.size() < 4 )
+ {
+ return false;
+ }
+
+ if ( mCurrentLabelPos.upsideDown )
+ {
+ pos = mCurrentLabelPos.cornerPoints.at( 2 );
+ }
+ else
+ {
+ pos = mCurrentLabelPos.cornerPoints.at( 0 );
+ }
+
+ //adapt pos depending on data defined alignment
+ QString haliString, valiString;
+ currentAlignment( haliString, valiString );
+
+ QFont labelFont = labelFontCurrentFeature();
+ QFontMetricsF labelFontMetrics( labelFont );
+
+ //label text?
+ QString labelText = currentLabelText();
+
+ bool labelSettingsOk;
+ QgsPalLayerSettings& labelSettings = currentLabelSettings( &labelSettingsOk );
+ if ( !labelSettingsOk )
+ {
+ return false;
+ }
+
+ double labelSizeX, labelSizeY;
+ labelSettings.calculateLabelSize( &labelFontMetrics, labelText, labelSizeX, labelSizeY );
+
+ double xdiff = 0;
+ double ydiff = 0;
+
+ if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
+ {
+ xdiff = labelSizeX / 2.0;
+ }
+ else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 )
+ {
+ xdiff = labelSizeX;
+ }
+
+ if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 )
+ {
+ ydiff = labelSizeY;
+ }
+ else
+ {
+ double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
+ if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 )
+ {
+ ydiff = labelSizeY * descentRatio;
+ }
+ else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 )
+ {
+ ydiff = labelSizeY * descentRatio;
+ ydiff = labelSizeY * 0.5 * ( 1 - descentRatio );
+ }
+ }
+
+ double angle = mCurrentLabelPos.rotation;
+ double xd = xdiff * cos( angle ) - ydiff * sin( angle );
+ double yd = xdiff * sin( angle ) + ydiff * cos( angle );
+ if ( mCurrentLabelPos.upsideDown )
+ {
+ pos.setX( pos.x() - xd );
+ pos.setY( pos.y() - yd );
+ }
+ else
+ {
+ pos.setX( pos.x() + xd );
+ pos.setY( pos.y() + yd );
+ }
+ return true;
+}
Added: trunk/qgis/src/app/qgsmaptoollabel.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoollabel.h (rev 0)
+++ trunk/qgis/src/app/qgsmaptoollabel.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,80 @@
+/***************************************************************************
+ qgsmaptoollabel.h
+ --------------------
+ begin : 2010-11-03
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QGSMAPTOOLLABEL_H
+#define QGSMAPTOOLLABEL_H
+
+#include "qgsmaptool.h"
+#include "qgsmaprenderer.h"
+#include "qgspallabeling.h"
+#include "qgspoint.h"
+class QgsRubberBand;
+
+/**Base class for map tools that modify label properties*/
+class QgsMapToolLabel: public QgsMapTool
+{
+ public:
+ QgsMapToolLabel( QgsMapCanvas* canvas );
+ ~QgsMapToolLabel();
+
+ protected:
+ QgsRubberBand* mLabelRubberBand;
+ QgsRubberBand* mFeatureRubberBand;
+ /**Shows label fixpoint (left/bottom by default)*/
+ QgsRubberBand* mFixPointRubberBand;
+
+ /**Currently dragged label position*/
+ QgsLabelPosition mCurrentLabelPos;
+
+ /**Returns label position for mouse click location
+ @param e mouse event
+ @param p out: label position
+ @return true in case of success, false if no label at this location*/
+ bool labelAtPosition( QMouseEvent* e, QgsLabelPosition& p );
+
+ /**Finds out rotation point of current label position
+ @return true in case of success*/
+ bool rotationPoint( QgsPoint& pos );
+
+ /**Creates label / feature / fixpoint rubber bands for the current label position*/
+ void createRubberBands();
+
+ /**Removes label / feature / fixpoint rubber bands*/
+ void deleteRubberBands();
+
+ /**Returns vector layer for current label position*/
+ QgsVectorLayer* currentLayer();
+
+ /**Returns layer settings of current label position*/
+ QgsPalLayerSettings& currentLabelSettings( bool* ok );
+
+ QString currentLabelText();
+
+ void currentAlignment( QString& hali, QString& vali );
+
+ /**Gets vector feature for current label pos
+ @return true in case of success*/
+ bool currentFeature( QgsFeature& f, bool fetchGeom = false );
+
+ /**Returns the font for the current feature (considering default font and data defined properties*/
+ QFont labelFontCurrentFeature();
+
+ private:
+ QgsPalLayerSettings mInvalidLabelSettings;
+};
+
+#endif // QGSMAPTOOLLABEL_H
Added: trunk/qgis/src/app/qgsmaptoolmovelabel.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolmovelabel.cpp (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolmovelabel.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,200 @@
+/***************************************************************************
+ qgsmaptoolmovelabel.cpp
+ -----------------------
+ begin : 2010-11-03
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "qgsmaptoolmovelabel.h"
+#include "qgsmapcanvas.h"
+#include "qgsmaplayerregistry.h"
+#include "qgsrubberband.h"
+#include "qgsvectorlayer.h"
+#include <QMouseEvent>
+
+QgsMapToolMoveLabel::QgsMapToolMoveLabel( QgsMapCanvas* canvas ): QgsMapToolLabel( canvas )
+{
+}
+
+QgsMapToolMoveLabel::~QgsMapToolMoveLabel()
+{
+}
+
+void QgsMapToolMoveLabel::canvasPressEvent( QMouseEvent * e )
+{
+ deleteRubberBands();
+
+ if ( !labelAtPosition( e, mCurrentLabelPos ) )
+ {
+ return;
+ }
+
+ QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID );
+ if ( !layer )
+ {
+ return;
+ }
+
+ int xCol, yCol;
+ if ( layerIsMoveable( layer, xCol, yCol ) )
+ {
+ mStartPointMapCoords = toMapCoordinates( e->pos() );
+ mClickOffsetX = mStartPointMapCoords.x() - mCurrentLabelPos.labelRect.xMinimum();
+ mClickOffsetY = mStartPointMapCoords.y() - mCurrentLabelPos.labelRect.yMinimum();
+ createRubberBands();
+ }
+}
+
+void QgsMapToolMoveLabel::canvasMoveEvent( QMouseEvent * e )
+{
+ if ( mLabelRubberBand )
+ {
+ QgsPoint pointCanvasCoords = toMapCoordinates( e->pos() );
+ double offsetX = pointCanvasCoords.x() - mStartPointMapCoords.x();
+ double offsetY = pointCanvasCoords.y() - mStartPointMapCoords.y();
+ mLabelRubberBand->setTranslationOffset( offsetX, offsetY );
+ mLabelRubberBand->updatePosition();
+ mLabelRubberBand->update();
+ mFixPointRubberBand->setTranslationOffset( offsetX, offsetY );
+ mFixPointRubberBand->updatePosition();
+ mFixPointRubberBand->update();
+ }
+}
+
+void QgsMapToolMoveLabel::canvasReleaseEvent( QMouseEvent * e )
+{
+ if ( !mLabelRubberBand )
+ {
+ return;
+ }
+
+ deleteRubberBands();
+
+ QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID );
+ if ( !layer )
+ {
+ return;
+ }
+
+ QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( layer );
+ if ( !vlayer )
+ {
+ return;
+ }
+
+ if ( !vlayer->isEditable() )
+ {
+ return;
+ }
+
+ QgsPoint releaseCoords = toMapCoordinates( e->pos() );
+ double xdiff = releaseCoords.x() - mStartPointMapCoords.x();
+ double ydiff = releaseCoords.y() - mStartPointMapCoords.y();
+
+ int xCol, yCol;
+ double xPosOrig, yPosOrig;
+ bool xSuccess, ySuccess;
+
+ if ( !dataDefinedPosition( vlayer, mCurrentLabelPos.featureId, xPosOrig, xSuccess, yPosOrig, ySuccess, xCol, yCol ) )
+ {
+ return;
+ }
+
+ double xPosNew, yPosNew;
+
+ if ( !xSuccess || !ySuccess )
+ {
+ xPosNew = releaseCoords.x() - mClickOffsetX;
+ yPosNew = releaseCoords.y() - mClickOffsetY;
+
+ //todo: consider hali/vali if there
+ }
+ else
+ {
+ xPosNew = xPosOrig + xdiff;
+ yPosNew = yPosOrig + ydiff;
+ }
+
+ vlayer->beginEditCommand( tr( "Label moved" ) );
+ vlayer->changeAttributeValue( mCurrentLabelPos.featureId, xCol, xPosNew, false );
+ vlayer->changeAttributeValue( mCurrentLabelPos.featureId, yCol, yPosNew, false );
+ vlayer->endEditCommand();
+
+ mCanvas->refresh();
+}
+
+bool QgsMapToolMoveLabel::dataDefinedPosition( QgsVectorLayer* vlayer, int featureId, double& x, bool& xSuccess, double& y, bool& ySuccess, int& xCol, int& yCol ) const
+{
+ xSuccess = false;
+ ySuccess = false;
+
+ if ( !vlayer )
+ {
+ return false;
+ }
+
+ if ( !layerIsMoveable( vlayer, xCol, yCol ) )
+ {
+ return false;
+ }
+
+ QgsFeature f;
+ if ( !vlayer->featureAtId( featureId, f, false, true ) )
+ {
+ return false;
+ }
+
+ QgsAttributeMap attributes = f.attributeMap();
+ x = attributes[xCol].toDouble( &xSuccess );
+ y = attributes[yCol].toDouble( &ySuccess );
+
+ return true;
+}
+
+bool QgsMapToolMoveLabel::layerIsMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const
+{
+ const QgsVectorLayer* vlayer = dynamic_cast<const QgsVectorLayer*>( ml );
+ if ( !vlayer || !vlayer->isEditable() )
+ {
+ return false;
+ }
+
+ bool xColOk, yColOk;
+
+ QVariant xColumn = ml->customProperty( "labeling/dataDefinedProperty9" );
+ if ( !xColumn.isValid() )
+ {
+ return false;
+ }
+ xCol = xColumn.toInt( &xColOk );
+ if ( !xColOk )
+ {
+ return false;
+ }
+
+ QVariant yColumn = ml->customProperty( "labeling/dataDefinedProperty10" );
+ if ( !yColumn.isValid() )
+ {
+ return false;
+ }
+ yCol = yColumn.toInt( &yColOk );
+ if ( !yColOk )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+
Added: trunk/qgis/src/app/qgsmaptoolmovelabel.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoolmovelabel.h (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolmovelabel.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,61 @@
+/***************************************************************************
+ qgsmaptoolmovelabel.h
+ --------------------
+ begin : 2010-11-03
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QGSMAPTOOLMOVELABEL_H
+#define QGSMAPTOOLMOVELABEL_H
+
+#include "qgsmaptoollabel.h"
+
+/**A map tool for dragging label positions*/
+class QgsMapToolMoveLabel: public QgsMapToolLabel
+{
+ public:
+ QgsMapToolMoveLabel( QgsMapCanvas* canvas );
+ ~QgsMapToolMoveLabel();
+
+ virtual void canvasPressEvent( QMouseEvent * e );
+
+ virtual void canvasMoveEvent( QMouseEvent * e );
+
+ virtual void canvasReleaseEvent( QMouseEvent * e );
+
+ protected:
+ /**Get data defined position of a feature
+ @param layerId layer identification string
+ @param x out: data defined x-coordinate
+ @param xSuccess out: false if attribute value is NULL
+ @param y out: data defined y-coordinate
+ @param ySuccess out: false if attribute value is NULL
+ @param xCol out: index of the x position column
+ @param yCol out: index of the y position column
+ @return false if layer does not have data defined label position enabled*/
+ bool dataDefinedPosition( QgsVectorLayer* vlayer, int featureId, double& x, bool& xSuccess, double& y, bool& ySuccess, int& xCol, int& yCol ) const;
+
+ /**Returns true if layer move can be applied to a layer
+ @param xCol out: index of the attribute for data defined x coordinate
+ @param yCol out: index of the attribute for data defined y coordinate
+ @return true if labels of layer can be moved*/
+ bool layerIsMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const;
+
+ /**Start point of the move in map coordinates*/
+ QgsPoint mStartPointMapCoords;
+
+ double mClickOffsetX;
+ double mClickOffsetY;
+};
+
+#endif // QGSMAPTOOLMOVELABEL_H
Added: trunk/qgis/src/app/qgsmaptoolrotatelabel.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolrotatelabel.cpp (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolrotatelabel.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,207 @@
+/***************************************************************************
+ qgsmaptoolrotatelabel.cpp
+ -------------------------
+ begin : 2010-11-09
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "qgsmaptoolrotatelabel.h"
+#include "qgsmapcanvas.h"
+#include "qgsmaplayerregistry.h"
+#include "qgspallabeling.h"
+#include "qgspointrotationitem.h"
+#include "qgsrubberband.h"
+#include "qgsvectorlayer.h"
+#include <QMouseEvent>
+
+#include "qgisapp.h"
+
+QgsMapToolRotateLabel::QgsMapToolRotateLabel( QgsMapCanvas* canvas ): QgsMapToolLabel( canvas ), mRotationItem( 0 )
+{
+}
+
+QgsMapToolRotateLabel::~QgsMapToolRotateLabel()
+{
+ delete mRotationItem;
+}
+
+void QgsMapToolRotateLabel::canvasPressEvent( QMouseEvent * e )
+{
+ deleteRubberBands();
+
+ if ( !labelAtPosition( e, mCurrentLabelPos ) )
+ {
+ return;
+ }
+
+ QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID ) );
+ if ( !vlayer )
+ {
+ return;
+ }
+
+ if ( !rotationPoint( mRotationPoint ) )
+ {
+ return;
+ }
+
+ int rotationCol;
+ if ( layerIsRotatable( vlayer, rotationCol ) )
+ {
+ mCurrentMouseAzimuth = azimuthToCCW( mRotationPoint.azimuth( toMapCoordinates( e->pos() ) ) );
+
+
+ bool hasRotationValue;
+ if ( dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, mCurrentRotation, hasRotationValue ) )
+ {
+ if ( !hasRotationValue )
+ {
+ mCurrentRotation = 0;
+ }
+ createRubberBands();
+
+ mRotationItem = new QgsPointRotationItem( mCanvas );
+ mRotationItem->setOrientation( QgsPointRotationItem::Counterclockwise );
+ mRotationItem->setSymbol( QgisApp::instance()->getThemePixmap( "mActionRotatePointSymbols.png" ).toImage() );
+ mRotationItem->setPointLocation( mRotationPoint );
+ mRotationItem->setSymbolRotation( mCurrentRotation );
+ }
+ }
+}
+
+void QgsMapToolRotateLabel::canvasMoveEvent( QMouseEvent * e )
+{
+ if ( mLabelRubberBand )
+ {
+ QgsPoint currentPoint = toMapCoordinates( e->pos() );
+ double azimuth = azimuthToCCW( mRotationPoint.azimuth( currentPoint ) );
+ double azimuthDiff = azimuth - mCurrentMouseAzimuth;
+ azimuthDiff = azimuthDiff > 180 ? azimuthDiff - 360 : azimuthDiff;
+
+ mCurrentRotation += azimuthDiff;
+ mCurrentRotation = mCurrentRotation - static_cast<float>( static_cast<int>( mCurrentRotation / 360 ) ) * 360; //mCurrentRotation % 360;
+ mCurrentRotation = mCurrentRotation < 0 ? 360 - mCurrentRotation : mCurrentRotation;
+
+ mCurrentMouseAzimuth = azimuth - static_cast<float>( static_cast<int>( azimuth / 360 ) ) * 360;
+
+ //if shift-modifier is pressed, round to 15 degrees
+ int displayValue;
+ if ( e->modifiers() & Qt::ControlModifier )
+ {
+ displayValue = roundTo15Degrees( mCurrentRotation );
+ mCtrlPressed = true;
+ }
+ else
+ {
+ displayValue = ( int )( mCurrentRotation );
+ mCtrlPressed = false;
+ }
+
+ if ( mRotationItem )
+ {
+ mRotationItem->setSymbolRotation( displayValue );
+ mRotationItem->update();
+ }
+ }
+}
+
+void QgsMapToolRotateLabel::canvasReleaseEvent( QMouseEvent * e )
+{
+ deleteRubberBands();
+ delete mRotationItem;
+ mRotationItem = 0;
+
+ QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID );
+ if ( !layer )
+ {
+ return;
+ }
+
+ QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( layer );
+ if ( !vlayer )
+ {
+ return;
+ }
+
+ int rotationCol;
+ if ( !layerIsRotatable( vlayer, rotationCol ) )
+ {
+ return;
+ }
+
+ double rotation = mCtrlPressed ? roundTo15Degrees( mCurrentRotation ) : mCurrentRotation;
+
+ vlayer->beginEditCommand( tr( "Label rotated" ) );
+ vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rotationCol, mCurrentRotation, false );
+ vlayer->endEditCommand();
+ mCanvas->refresh();
+}
+
+bool QgsMapToolRotateLabel::layerIsRotatable( const QgsMapLayer* layer, int& rotationCol ) const
+{
+ const QgsVectorLayer* vlayer = dynamic_cast<const QgsVectorLayer*>( layer );
+ if ( !vlayer || !vlayer->isEditable() )
+ {
+ return false;
+ }
+
+ QVariant rotation = layer->customProperty( "labeling/dataDefinedProperty14" );
+ if ( !rotation.isValid() )
+ {
+ return false;
+ }
+
+ bool rotationOk;
+ rotationCol = rotation.toInt( &rotationOk );
+ if ( !rotationOk )
+ {
+ return false;
+ }
+ return true;
+}
+
+bool QgsMapToolRotateLabel::dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess )
+{
+ rotationSuccess = false;
+ if ( !vlayer )
+ {
+ return false;
+ }
+
+ int rotationCol;
+ if ( !layerIsRotatable( vlayer, rotationCol ) )
+ {
+ return false;
+ }
+
+ QgsFeature f;
+ if ( !vlayer->featureAtId( featureId, f, false, true ) )
+ {
+ return false;
+ }
+
+ QgsAttributeMap attributes = f.attributeMap();
+ rotation = attributes[rotationCol].toDouble( &rotationSuccess );
+ return true;
+}
+
+int QgsMapToolRotateLabel::roundTo15Degrees( double n )
+{
+ int m = ( int )( n / 15.0 + 0.5 );
+ return ( m * 15 );
+}
+
+double QgsMapToolRotateLabel::azimuthToCCW( double a )
+{
+ return ( a > 0 ? 360 - a : -a );
+}
Added: trunk/qgis/src/app/qgsmaptoolrotatelabel.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoolrotatelabel.h (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolrotatelabel.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,59 @@
+/***************************************************************************
+ qgsmaptoolrotatelabel.h
+ -----------------------
+ begin : 2010-11-09
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QGSMAPTOOLROTATELABEL_H
+#define QGSMAPTOOLROTATELABEL_H
+
+#include "qgsmaptoollabel.h"
+class QgsPointRotationItem;
+
+class QgsMapToolRotateLabel: public QgsMapToolLabel
+{
+ public:
+ QgsMapToolRotateLabel( QgsMapCanvas* canvas );
+ ~QgsMapToolRotateLabel();
+
+ virtual void canvasPressEvent( QMouseEvent * e );
+ virtual void canvasMoveEvent( QMouseEvent * e );
+ virtual void canvasReleaseEvent( QMouseEvent * e );
+
+ protected:
+ /**Checks if labels in a layer can be rotated
+ @param rotationCol out: attribute column for data defined label rotation*/
+ bool layerIsRotatable( const QgsMapLayer* layer, int& rotationCol ) const;
+ /**Returns data defined rotation of a feature.
+ @param rotation out: rotation value
+ @param rotationSuccess out: false if rotation value is NULL
+ @return true if data defined rotation is enabled on the layer
+ */
+ bool dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess );
+
+ static int roundTo15Degrees( double n );
+ /**Converts azimuth value to counterclockwise 0 - 360*/
+ static double azimuthToCCW( double a );
+
+
+ double mCurrentRotation;
+ double mCurrentMouseAzimuth;
+ QgsPoint mRotationPoint;
+ QgsPointRotationItem* mRotationItem;
+
+ /**True if ctrl was pressed during the last mouse move event*/
+ bool mCtrlPressed;
+};
+
+#endif // QGSMAPTOOLROTATELABEL_H
Modified: trunk/qgis/src/app/qgspointrotationitem.cpp
===================================================================
--- trunk/qgis/src/app/qgspointrotationitem.cpp 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/app/qgspointrotationitem.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -22,7 +22,7 @@
#include <math.h>
#endif
-QgsPointRotationItem::QgsPointRotationItem( QgsMapCanvas* canvas ): QgsMapCanvasItem( canvas ), mRotation( 0.0 )
+QgsPointRotationItem::QgsPointRotationItem( QgsMapCanvas* canvas ): QgsMapCanvasItem( canvas ), mOrientation( Clockwise ), mRotation( 0.0 )
{
//setup font
mFont.setPointSize( 12 );
@@ -55,12 +55,11 @@
{
h = sqrt(( double ) mPixmap.width() * mPixmap.width() + mPixmap.height() * mPixmap.height() ) / 2; //the half of the item diagonal
dAngel = acos( mPixmap.width() / ( h * 2 ) ) * 180 / M_PI; //the diagonal angel of the original rect
- x = h * cos(( mRotation - dAngel ) * M_PI / 180 );
- y = h * sin(( mRotation - dAngel ) * M_PI / 180 );
+ x = h * cos(( painterRotation( mRotation ) - dAngel ) * M_PI / 180 );
+ y = h * sin(( painterRotation( mRotation ) - dAngel ) * M_PI / 180 );
}
- //painter->translate(-mPixmap.width() / 2.0, -mPixmap.width() / 2.0);
- painter->rotate( mRotation );
+ painter->rotate( painterRotation( mRotation ) );
painter->translate( x - mPixmap.width() / 2.0, -y - mPixmap.height() / 2.0 );
painter->drawPixmap( 0, 0, mPixmap );
@@ -109,3 +108,13 @@
}
}
+int QgsPointRotationItem::painterRotation( int rotation ) const
+{
+ if ( mOrientation == Clockwise )
+ {
+ return rotation;
+ }
+
+ return 360 - ( rotation % 360 );
+}
+
Modified: trunk/qgis/src/app/qgspointrotationitem.h
===================================================================
--- trunk/qgis/src/app/qgspointrotationitem.h 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/app/qgspointrotationitem.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -24,6 +24,13 @@
class QgsPointRotationItem: public QgsMapCanvasItem
{
public:
+
+ enum Orientation
+ {
+ Clockwise = 0,
+ Counterclockwise
+ };
+
QgsPointRotationItem( QgsMapCanvas* canvas );
~QgsPointRotationItem();
@@ -39,8 +46,15 @@
/**Sets rotation symbol from image (takes ownership)*/
void setSymbol( const QImage& symbolImage );
+ void setOrientation( Orientation o ) { mOrientation = o; }
+ Orientation orientation() const { return mOrientation; }
+
private:
QgsPointRotationItem();
+ /**Converts rotation into QPainter rotation considering mOrientation*/
+ int painterRotation( int rotation ) const;
+ /**Clockwise (default) or counterclockwise*/
+ Orientation mOrientation;
/**Font to display the numerical rotation values*/
QFont mFont;
/**Symboll pixmap*/
Modified: trunk/qgis/src/core/CMakeLists.txt
===================================================================
--- trunk/qgis/src/core/CMakeLists.txt 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/CMakeLists.txt 2010-11-17 15:01:15 UTC (rev 14697)
@@ -53,6 +53,7 @@
qgshttptransaction.cpp
qgslabel.cpp
qgslabelattributes.cpp
+ qgslabelsearchtree.cpp
qgslogger.cpp
qgsmaplayer.cpp
qgsmaplayerregistry.cpp
Modified: trunk/qgis/src/core/pal/labelposition.cpp
===================================================================
--- trunk/qgis/src/core/pal/labelposition.cpp 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/pal/labelposition.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -55,7 +55,7 @@
namespace pal
{
LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature, bool isReversed )
- : id( id ), cost( cost ), feature( feature ), nbOverlap( 0 ), alpha( alpha ), w( w ), h( h ), nextPart( NULL ), partId( -1 ), reversed( isReversed )
+ : id( id ), cost( cost ), feature( feature ), nbOverlap( 0 ), alpha( alpha ), w( w ), h( h ), nextPart( NULL ), partId( -1 ), reversed( isReversed ), upsideDown( false )
{
// alpha take his value bw 0 and 2*pi rad
@@ -111,6 +111,8 @@
x[3] = tx;
y[3] = ty;
+ upsideDown = true;
+
if ( this->alpha < M_PI )
this->alpha += M_PI;
else
@@ -137,6 +139,7 @@
else
nextPart = NULL;
partId = other.partId;
+ upsideDown = other.upsideDown;
}
bool LabelPosition::isIn( double *bbox )
Modified: trunk/qgis/src/core/pal/labelposition.h
===================================================================
--- trunk/qgis/src/core/pal/labelposition.h 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/pal/labelposition.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -79,6 +79,8 @@
//if the layer arrangement is P_LINE
bool reversed;
+ bool upsideDown;
+
bool isInConflictSinglePart( LabelPosition* lp );
bool isInConflictMultiPart( LabelPosition* lp );
@@ -196,6 +198,7 @@
*/
double getAlpha() const;
bool getReversed() const { return reversed; }
+ bool getUpsideDown() const { return upsideDown; }
void print();
Added: trunk/qgis/src/core/qgslabelsearchtree.cpp
===================================================================
--- trunk/qgis/src/core/qgslabelsearchtree.cpp (rev 0)
+++ trunk/qgis/src/core/qgslabelsearchtree.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,62 @@
+#include "qgslabelsearchtree.h"
+#include "labelposition.h"
+
+bool searchCallback( QgsLabelPosition* pos, void* context )
+{
+ QList<QgsLabelPosition*>* list = static_cast< QList<QgsLabelPosition*>* >( context );
+ list->push_back( pos );
+ return true;
+}
+
+QgsLabelSearchTree::QgsLabelSearchTree()
+{
+}
+
+QgsLabelSearchTree::~QgsLabelSearchTree()
+{
+ clear();
+}
+
+void QgsLabelSearchTree::label( const QgsPoint& p, QList<QgsLabelPosition*>& posList )
+{
+ double c_min[2]; c_min[0] = p.x() - 1; c_min[1] = p.y() - 1;
+ double c_max[2]; c_max[0] = p.x() + 1; c_max[1] = p.y() + 1;
+
+ mSearchResults.clear();
+ mSpatialIndex.Search( c_min, c_max, searchCallback, &mSearchResults );
+ posList = mSearchResults;
+}
+
+bool QgsLabelSearchTree::insertLabel( LabelPosition* labelPos, int featureId, const QString& layerName )
+{
+ if ( !labelPos )
+ {
+ return false;
+ }
+
+ double c_min[2];
+ double c_max[2];
+ labelPos->getBoundingBox( c_min, c_max );
+
+ QVector<QgsPoint> cornerPoints;
+ for ( int i = 0; i < 4; ++i )
+ {
+ cornerPoints.push_back( QgsPoint( labelPos->getX( i ), labelPos->getY( i ) ) );
+ }
+ QgsLabelPosition* newEntry = new QgsLabelPosition( featureId, labelPos->getAlpha(), cornerPoints, QgsRectangle( c_min[0], c_min[1], c_max[0], c_max[1] ),
+ labelPos->getWidth(), labelPos->getHeight(), layerName, labelPos->getUpsideDown() );
+ mSpatialIndex.Insert( c_min, c_max, newEntry );
+ return true;
+}
+
+void QgsLabelSearchTree::clear()
+{
+ RTree<QgsLabelPosition*, double, 2, double>::Iterator indexIt;
+ mSpatialIndex.GetFirst( indexIt );
+ while ( !mSpatialIndex.IsNull( indexIt ) )
+ {
+ delete mSpatialIndex.GetAt( indexIt );
+ mSpatialIndex.GetNext( indexIt );
+ }
+ mSpatialIndex.RemoveAll();
+}
Added: trunk/qgis/src/core/qgslabelsearchtree.h
===================================================================
--- trunk/qgis/src/core/qgslabelsearchtree.h (rev 0)
+++ trunk/qgis/src/core/qgslabelsearchtree.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,54 @@
+/***************************************************************************
+ qgslabelsearchtree.h
+ Node for raster calculator tree
+ --------------------
+ begin : 2010-11-02
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole dot ch
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QGSLABELSEARCHTREE_H
+#define QGSLABELSEARCHTREE_H
+
+#include "qgspoint.h"
+#include "qgsmaprenderer.h"
+#include <QList>
+#include <QVector>
+#include <pointset.h>
+#include <labelposition.h>
+#include "qgsrectangle.h"
+
+using namespace pal;
+
+/**A class to query the labeling structure at a given point (small wraper around pal RTree class)*/
+class QgsLabelSearchTree
+{
+ public:
+ QgsLabelSearchTree();
+ ~QgsLabelSearchTree();
+
+ /**Removes and deletes all the entries*/
+ void clear();
+
+ /**Returns label position(s) at a given point. QgsLabelSearchTree keeps ownership, don't delete the LabelPositions*/
+ void label( const QgsPoint& p, QList<QgsLabelPosition*>& posList );
+
+ /**Inserts label position. Does not take ownership of labelPos
+ @return true in case of success*/
+ bool insertLabel( LabelPosition* labelPos, int featureId, const QString& layerName );
+
+ private:
+ RTree<QgsLabelPosition*, double, 2, double> mSpatialIndex;
+ QList<QgsLabelPosition*> mSearchResults;
+};
+
+#endif // QGSLABELTREE_H
Modified: trunk/qgis/src/core/qgsmaprenderer.h
===================================================================
--- trunk/qgis/src/core/qgsmaprenderer.h 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/qgsmaprenderer.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -19,6 +19,7 @@
#include <QSize>
#include <QStringList>
+#include <QVector>
#include "qgis.h"
#include "qgsrectangle.h"
@@ -38,12 +39,28 @@
class QgsVectorLayer;
class QgsFeature;
+struct QgsLabelPosition
+{
+ QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, bool upside_down ):
+ featureId( id ), rotation( r ), cornerPoints( corners ), labelRect( rect ), width( w ), height( h ), layerID( layer ), upsideDown( upside_down ) {}
+ QgsLabelPosition(): featureId( -1 ), rotation( 0 ), labelRect( QgsRectangle() ), width( 0 ), height( 0 ), layerID( "" ), upsideDown( false ) {}
+ int featureId;
+ double rotation;
+ QVector< QgsPoint > cornerPoints;
+ QgsRectangle labelRect;
+ double width;
+ double height;
+ QString layerID;
+ bool upsideDown;
+};
+
/** Labeling engine interface.
* \note Added in QGIS v1.4
*/
class QgsLabelingEngineInterface
{
public:
+
virtual ~QgsLabelingEngineInterface() {}
//! called when we're going to start with rendering
@@ -59,6 +76,9 @@
virtual void drawLabeling( QgsRenderContext& context ) = 0;
//! called when we're done with rendering
virtual void exit() = 0;
+ //! return infos about labels at a given (map) position
+ //! @note: this method was added in version 1.7
+ virtual QList<QgsLabelPosition> labelsAtPosition( const QgsPoint& p ) = 0;
//! called when passing engine among map renderers
virtual QgsLabelingEngineInterface* clone() = 0;
Modified: trunk/qgis/src/core/qgspallabeling.cpp
===================================================================
--- trunk/qgis/src/core/qgspallabeling.cpp 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/qgspallabeling.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -38,6 +38,7 @@
#include <QTime>
#include <QPainter>
+#include "qgslabelsearchtree.h"
#include <qgslogger.h>
#include <qgsvectorlayer.h>
#include <qgsmaplayerregistry.h>
@@ -453,6 +454,7 @@
bool dataDefinedPosition = false;
bool dataDefinedRotation = false;
double xPos, yPos, angle;
+ bool ddXPos, ddYPos;
QMap< DataDefinedProperties, int >::const_iterator dPosXIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionX );
if ( dPosXIt != dataDefinedProperties.constEnd() )
@@ -460,74 +462,77 @@
QMap< DataDefinedProperties, int >::const_iterator dPosYIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionY );
if ( dPosYIt != dataDefinedProperties.constEnd() )
{
- //data defined position
- dataDefinedPosition = true;
- xPos = f.attributeMap().value( *dPosXIt ).toDouble();
- yPos = f.attributeMap().value( *dPosYIt ).toDouble();
+ //data defined position. But field values could be NULL -> positions will be generated by PAL
+ xPos = f.attributeMap().value( *dPosXIt ).toDouble( &ddXPos );
+ yPos = f.attributeMap().value( *dPosYIt ).toDouble( &ddYPos );
- //x/y shift in case of alignment
- double xdiff = 0;
- double ydiff = 0;
-
- //horizontal alignment
- QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali );
- if ( haliIt != dataDefinedProperties.end() )
+ if ( ddXPos && ddYPos )
{
- QString haliString = f.attributeMap().value( *haliIt ).toString();
- if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
- {
- xdiff -= labelX / 2.0;
- }
- else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 )
- {
- xdiff -= labelX;
- }
- }
+ dataDefinedPosition = true;
+ //x/y shift in case of alignment
+ double xdiff = 0;
+ double ydiff = 0;
- //vertical alignment
- QMap< DataDefinedProperties, int >::const_iterator valiIt = dataDefinedProperties.find( QgsPalLayerSettings::Vali );
- if ( valiIt != dataDefinedProperties.constEnd() )
- {
- QString valiString = f.attributeMap().value( *valiIt ).toString();
- if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 )
+ //horizontal alignment
+ QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali );
+ if ( haliIt != dataDefinedProperties.end() )
{
- if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 )
+ QString haliString = f.attributeMap().value( *haliIt ).toString();
+ if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
{
- ydiff -= labelY;
+ xdiff -= labelX / 2.0;
}
- else
+ else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 )
{
- QFontMetrics labelFontMetrics( labelFont );
- double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
+ xdiff -= labelX;
+ }
+ }
- if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 )
+ //vertical alignment
+ QMap< DataDefinedProperties, int >::const_iterator valiIt = dataDefinedProperties.find( QgsPalLayerSettings::Vali );
+ if ( valiIt != dataDefinedProperties.constEnd() )
+ {
+ QString valiString = f.attributeMap().value( *valiIt ).toString();
+ if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 )
+ {
+ if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 )
{
- ydiff -= labelY * descentRatio;
+ ydiff -= labelY;
}
- else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 )
+ else
{
- ydiff -= labelY * descentRatio;
- ydiff -= labelY * 0.5 * ( 1 - descentRatio );
+ QFontMetrics labelFontMetrics( labelFont );
+ double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
+
+ if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 )
+ {
+ ydiff -= labelY * descentRatio;
+ }
+ else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 )
+ {
+ ydiff -= labelY * descentRatio;
+ ydiff -= labelY * 0.5 * ( 1 - descentRatio );
+ }
}
}
}
- }
- //data defined rotation?
- QMap< DataDefinedProperties, int >::const_iterator rotIt = dataDefinedProperties.find( QgsPalLayerSettings::Rotation );
- if ( rotIt != dataDefinedProperties.constEnd() )
- {
- dataDefinedRotation = true;
- angle = f.attributeMap().value( *rotIt ).toDouble() * M_PI / 180;
- //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center
- double xd = xdiff * cos( angle ) - ydiff * sin( angle );
- double yd = xdiff * sin( angle ) + ydiff * cos( angle );
- xdiff = xd;
- ydiff = yd;
+ //data defined rotation?
+ QMap< DataDefinedProperties, int >::const_iterator rotIt = dataDefinedProperties.find( QgsPalLayerSettings::Rotation );
+ if ( rotIt != dataDefinedProperties.constEnd() )
+ {
+ dataDefinedRotation = true;
+ angle = f.attributeMap().value( *rotIt ).toDouble() * M_PI / 180;
+ //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center
+ double xd = xdiff * cos( angle ) - ydiff * sin( angle );
+ double yd = xdiff * sin( angle ) + ydiff * cos( angle );
+ xdiff = xd;
+ ydiff = yd;
+ }
+
+ yPos += ydiff;
+ xPos += xdiff;
}
-
- yPos += ydiff;
- xPos += xdiff;
}
}
@@ -615,6 +620,8 @@
mShowingCandidates = false;
mShowingAllLabels = false;
+
+ mLabelSearchTree = new QgsLabelSearchTree();
}
@@ -622,6 +629,8 @@
{
// make sure we've freed everything
exit();
+ delete mLabelSearchTree;
+ mLabelSearchTree = NULL;
}
@@ -752,6 +761,8 @@
mPal->setPointP( mCandPoint );
mPal->setLineP( mCandLine );
mPal->setPolyP( mCandPolygon );
+
+ mActiveLayers.clear();
}
void QgsPalLabeling::exit()
@@ -761,14 +772,15 @@
mMapRenderer = NULL;
}
-QgsPalLayerSettings& QgsPalLabeling::layer( const char* layerName )
+QgsPalLayerSettings& QgsPalLabeling::layer( const QString& layerName )
{
QHash<QgsVectorLayer*, QgsPalLayerSettings>::iterator lit;
for ( lit = mActiveLayers.begin(); lit != mActiveLayers.end(); ++lit )
{
- QgsPalLayerSettings& lyr = lit.value();
- if ( lyr.palLayer->getName() == layerName )
- return lyr;
+ if ( lit.key() && lit.key()->getLayerID() == layerName )
+ {
+ return lit.value();
+ }
}
return mInvalidLayerSettings;
}
@@ -780,6 +792,11 @@
QPainter* painter = context.painter();
QgsRectangle extent = context.extent();
+ if ( mLabelSearchTree )
+ {
+ mLabelSearchTree->clear();
+ }
+
QTime t;
t.start();
@@ -797,7 +814,7 @@
catch ( std::exception& e )
{
QgsDebugMsg( "PAL EXCEPTION :-( " + QString::fromLatin1( e.what() ) );
- mActiveLayers.clear(); // clean up
+ //mActiveLayers.clear(); // clean up
return;
}
@@ -915,6 +932,11 @@
drawLabel( *it, painter, fontForLabel, fontColor, xform, bufferSize, bufferColor, true );
drawLabel( *it, painter, fontForLabel, fontColor, xform );
+
+ if ( mLabelSearchTree )
+ {
+ mLabelSearchTree->insertLabel( *it, QString( palGeometry->strId() ).toInt(), ( *it )->getLayerName() );
+ }
}
QgsDebugMsg( QString( "LABELING draw: %1 ms" ).arg( t.elapsed() ) );
@@ -932,10 +954,28 @@
lyr.geometries.clear();
}
// labeling is done: clear the active layers hashtable
- mActiveLayers.clear();
+// mActiveLayers.clear();
}
+QList<QgsLabelPosition> QgsPalLabeling::labelsAtPosition( const QgsPoint& p )
+{
+ QList<QgsLabelPosition> positions;
+
+ QList<QgsLabelPosition*> positionPointers;
+ if ( mLabelSearchTree )
+ {
+ mLabelSearchTree->label( p, positionPointers );
+ QList<QgsLabelPosition*>::const_iterator pointerIt = positionPointers.constBegin();
+ for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
+ {
+ positions.push_back( QgsLabelPosition( **pointerIt ) );
+ }
+ }
+
+ return positions;
+}
+
void QgsPalLabeling::numCandidatePositions( int& candPoint, int& candLine, int& candPolygon )
{
candPoint = mCandPoint;
@@ -1055,14 +1095,6 @@
void QgsPalLabeling::drawLabelBuffer( QPainter* p, QString text, const QFont& font, double size, QColor color )
{
- /*
- p->setFont( font );
- p->setPen( color );
- for (int x = -size; x <= size; x++)
- for (int y = -size; y <= size; y++)
- p->drawText(x,y, text);
- */
-
QPainterPath path;
path.addText( 0, 0, font, text );
QPen pen( color );
Modified: trunk/qgis/src/core/qgspallabeling.h
===================================================================
--- trunk/qgis/src/core/qgspallabeling.h 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/qgspallabeling.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -26,6 +26,7 @@
class QgsMapRenderer;
class QgsRectangle;
class QgsCoordinateTransform;
+class QgsLabelSearchTree;
#include <QString>
#include <QFont>
@@ -168,7 +169,7 @@
QgsPalLabeling();
~QgsPalLabeling();
- QgsPalLayerSettings& layer( const char* layerName );
+ QgsPalLayerSettings& layer( const QString& layerName );
void numCandidatePositions( int& candPoint, int& candLine, int& candPolygon );
void setNumCandidatePositions( int candPoint, int candLine, int candPolygon );
@@ -199,6 +200,8 @@
virtual void drawLabeling( QgsRenderContext& context );
//! called when we're done with rendering
virtual void exit();
+ //! return infos about labels at a given (map) position
+ virtual QList<QgsLabelPosition> labelsAtPosition( const QgsPoint& p );
//! called when passing engine among map renderers
virtual QgsLabelingEngineInterface* clone();
@@ -214,7 +217,7 @@
void initPal();
protected:
- // temporary hashtable of layer settings, being filled during labeling, cleared once labeling's done
+ // hashtable of layer settings, being filled during labeling
QHash<QgsVectorLayer*, QgsPalLayerSettings> mActiveLayers;
QgsPalLayerSettings mInvalidLayerSettings;
@@ -229,6 +232,8 @@
bool mShowingCandidates;
bool mShowingAllLabels; // whether to avoid collisions or not
+
+ QgsLabelSearchTree* mLabelSearchTree;
};
#endif // QGSPALLABELING_H
Modified: trunk/qgis/src/core/qgspoint.cpp
===================================================================
--- trunk/qgis/src/core/qgspoint.cpp 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/qgspoint.cpp 2010-11-17 15:01:15 UTC (rev 14697)
@@ -43,7 +43,7 @@
QgsVector QgsVector::operator*( double scalar ) const
{
- return QgsVector( m_x*scalar, m_y*scalar );
+ return QgsVector( m_x * scalar, m_y * scalar );
}
QgsVector QgsVector::operator/( double scalar ) const
@@ -53,12 +53,12 @@
double QgsVector::operator*( QgsVector v ) const
{
- return m_x*v.m_x + m_y*v.m_y;
+ return m_x * v.m_x + m_y * v.m_y;
}
double QgsVector::length() const
{
- return sqrt( m_x*m_x + m_y*m_y );
+ return sqrt( m_x * m_x + m_y * m_y );
}
double QgsVector::x() const
@@ -80,7 +80,7 @@
double QgsVector::angle( void ) const
{
double ang = atan2( m_y, m_x );
- return ang < 0.0 ? ang + 2.0*M_PI : ang;
+ return ang < 0.0 ? ang + 2.0 * M_PI : ang;
}
double QgsVector::angle( QgsVector v ) const
@@ -92,7 +92,7 @@
{
double ang = atan2( m_y, m_x ) + rot;
double len = length();
- return QgsVector( len*cos( ang ), len*sin( ang ) );
+ return QgsVector( len * cos( ang ), len * sin( ang ) );
}
QgsVector QgsVector::normal() const
@@ -167,7 +167,7 @@
double QgsPoint::sqrDist( double x, double y ) const
{
- return ( m_x - x )*( m_x - x ) + ( m_y - y )*( m_y - y );
+ return ( m_x - x ) * ( m_x - x ) + ( m_y - y ) * ( m_y - y );
}
double QgsPoint::sqrDist( const QgsPoint& other ) const
@@ -175,6 +175,13 @@
return sqrDist( other.x(), other.y() );
}
+double QgsPoint::azimuth( const QgsPoint& other )
+{
+ double dx = other.x() - m_x;
+ double dy = other.y() - m_y;
+ return ( atan2( dx, dy ) * 180.0 / M_PI );
+}
+
// operators
bool QgsPoint::operator==( const QgsPoint & other )
{
Modified: trunk/qgis/src/core/qgspoint.h
===================================================================
--- trunk/qgis/src/core/qgspoint.h 2010-11-17 09:57:44 UTC (rev 14696)
+++ trunk/qgis/src/core/qgspoint.h 2010-11-17 15:01:15 UTC (rev 14697)
@@ -148,6 +148,10 @@
@note added in QGIS 1.5*/
double sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint ) const;
+ /**Calculates azimut between this point and other one (clockwise in degree, starting from north)
+ @note: this function has been added in version 1.7*/
+ double azimuth( const QgsPoint& other );
+
//! equality operator
bool operator==( const QgsPoint &other );
Added: trunk/qgis/src/ui/qgslabelpropertydialogbase.ui
===================================================================
--- trunk/qgis/src/ui/qgslabelpropertydialogbase.ui (rev 0)
+++ trunk/qgis/src/ui/qgslabelpropertydialogbase.ui 2010-11-17 15:01:15 UTC (rev 14697)
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QgsLabelPropertyDialogBase</class>
+ <widget class="QDialog" name="QgsLabelPropertyDialogBase">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>284</width>
+ <height>411</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Label properties</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="mLabelTextLabel">
+ <property name="text">
+ <string>Text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="mLabelTextLineEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QGroupBox" name="mFontGroupBox">
+ <property name="title">
+ <string>Font</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="mFontSizeLabel">
+ <property name="text">
+ <string>Size</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="mFontSizeSpinBox">
+ <property name="maximum">
+ <double>999999.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="mFontPushButton">
+ <property name="text">
+ <string>Font</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QgsColorButton" name="mFontColorButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QGroupBox" name="mBufferGroupBox">
+ <property name="title">
+ <string>Buffer</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="mBufferSizeLabel">
+ <property name="text">
+ <string>Size</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="mBufferSizeSpinBox">
+ <property name="maximum">
+ <double>999999.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <widget class="QgsColorButton" name="mBufferColorButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QGroupBox" name="mPositionGroupBlox">
+ <property name="title">
+ <string>Position</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="mLabelDistanceLabel">
+ <property name="text">
+ <string>Label distance</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QDoubleSpinBox" name="mLabelDistanceSpinBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="mXCoordLabel">
+ <property name="text">
+ <string>X Coordinate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QDoubleSpinBox" name="mXCoordSpinBox">
+ <property name="minimum">
+ <double>-999999999.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>999999999.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="mYCoordLabel">
+ <property name="text">
+ <string>Y Coordinate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QDoubleSpinBox" name="mYCoordSpinBox">
+ <property name="minimum">
+ <double>-999999999.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>999999999.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="mHaliLabel">
+ <property name="text">
+ <string>Horizontal alignment</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QComboBox" name="mHaliComboBox"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="mValiLabel">
+ <property name="text">
+ <string>Vertical alignment</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QComboBox" name="mValiComboBox"/>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="mRotationLabel">
+ <property name="text">
+ <string>Rotation</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QDoubleSpinBox" name="mRotationSpinBox">
+ <property name="maximum">
+ <double>360.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QgsColorButton</class>
+ <extends>QToolButton</extends>
+ <header>qgscolorbutton.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QgsLabelPropertyDialogBase</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QgsLabelPropertyDialogBase</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
More information about the QGIS-commit
mailing list