From a62efcd455fa2ef7ccd6adefeb4342bc50c3bb69 Mon Sep 17 00:00:00 2001 From: mhugent Date: Thu, 9 Dec 2010 16:07:27 +0000 Subject: [PATCH] Little improvement for label preview (box), better handling of situations where rotation is not possible git-svn-id: http://svn.osgeo.org/qgis/trunk@14877 c8812cc2-4d05-0410-92ff-de0c093fc19c --- src/app/qgsmaptoollabel.cpp | 63 +++++++++++++++++++++++++ src/app/qgsmaptoollabel.h | 17 +++++++ src/app/qgsmaptoolmovelabel.cpp | 65 -------------------------- src/app/qgsmaptoolmovelabel.h | 16 ------- src/app/qgsmaptoolrotatelabel.cpp | 78 ++++++++++++++++++++++++++++++- src/app/qgsmaptoolrotatelabel.h | 7 +++ 6 files changed, 164 insertions(+), 82 deletions(-) diff --git a/src/app/qgsmaptoollabel.cpp b/src/app/qgsmaptoollabel.cpp index 392e601b0604..a49df0faac8e 100644 --- a/src/app/qgsmaptoollabel.cpp +++ b/src/app/qgsmaptoollabel.cpp @@ -345,3 +345,66 @@ bool QgsMapToolLabel::rotationPoint( QgsPoint& pos ) } return true; } + +bool QgsMapToolLabel::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 QgsMapToolLabel::layerIsMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const +{ + const QgsVectorLayer* vlayer = dynamic_cast( 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; +} diff --git a/src/app/qgsmaptoollabel.h b/src/app/qgsmaptoollabel.h index a4052e3c9f64..4b42777078e6 100644 --- a/src/app/qgsmaptoollabel.h +++ b/src/app/qgsmaptoollabel.h @@ -31,6 +31,12 @@ class QgsMapToolLabel: public QgsMapTool QgsMapToolLabel( QgsMapCanvas* canvas ); ~QgsMapToolLabel(); + /**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; + protected: QgsRubberBand* mLabelRubberBand; QgsRubberBand* mFeatureRubberBand; @@ -73,6 +79,17 @@ class QgsMapToolLabel: public QgsMapTool /**Returns the font for the current feature (considering default font and data defined properties*/ QFont labelFontCurrentFeature(); + /**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; + private: QgsPalLayerSettings mInvalidLabelSettings; }; diff --git a/src/app/qgsmaptoolmovelabel.cpp b/src/app/qgsmaptoolmovelabel.cpp index 1c48e2c7058d..f6db3ac1d46a 100644 --- a/src/app/qgsmaptoolmovelabel.cpp +++ b/src/app/qgsmaptoolmovelabel.cpp @@ -116,8 +116,6 @@ void QgsMapToolMoveLabel::canvasReleaseEvent( QMouseEvent * e ) { xPosNew = releaseCoords.x() - mClickOffsetX; yPosNew = releaseCoords.y() - mClickOffsetY; - - //todo: consider hali/vali if there } else { @@ -133,68 +131,5 @@ void QgsMapToolMoveLabel::canvasReleaseEvent( QMouseEvent * e ) 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( 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; -} - diff --git a/src/app/qgsmaptoolmovelabel.h b/src/app/qgsmaptoolmovelabel.h index b8d7abec2707..d39cca2dc991 100644 --- a/src/app/qgsmaptoolmovelabel.h +++ b/src/app/qgsmaptoolmovelabel.h @@ -35,23 +35,7 @@ class QgsMapToolMoveLabel: public QgsMapToolLabel virtual void canvasReleaseEvent( QMouseEvent * e ); - /**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; - 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; /**Start point of the move in map coordinates*/ QgsPoint mStartPointMapCoords; diff --git a/src/app/qgsmaptoolrotatelabel.cpp b/src/app/qgsmaptoolrotatelabel.cpp index 062020b4e02a..89696bff8f8b 100644 --- a/src/app/qgsmaptoolrotatelabel.cpp +++ b/src/app/qgsmaptoolrotatelabel.cpp @@ -26,13 +26,14 @@ #include "qgisapp.h" -QgsMapToolRotateLabel::QgsMapToolRotateLabel( QgsMapCanvas* canvas ): QgsMapToolLabel( canvas ), mRotationItem( 0 ) +QgsMapToolRotateLabel::QgsMapToolRotateLabel( QgsMapCanvas* canvas ): QgsMapToolLabel( canvas ), mRotationItem( 0 ), mRotationPreviewBox( 0 ) { } QgsMapToolRotateLabel::~QgsMapToolRotateLabel() { delete mRotationItem; + delete mRotationPreviewBox; } void QgsMapToolRotateLabel::canvasPressEvent( QMouseEvent * e ) @@ -68,8 +69,11 @@ void QgsMapToolRotateLabel::canvasPressEvent( QMouseEvent * e ) { mCurrentRotation = 0; } + mStartRotation = mCurrentRotation; createRubberBands(); + mRotationPreviewBox = createRotationPreviewBox(); + mRotationItem = new QgsPointRotationItem( mCanvas ); mRotationItem->setOrientation( QgsPointRotationItem::Counterclockwise ); mRotationItem->setSymbol( QgisApp::instance()->getThemePixmap( "mActionRotatePointSymbols.png" ).toImage() ); @@ -110,6 +114,7 @@ void QgsMapToolRotateLabel::canvasMoveEvent( QMouseEvent * e ) if ( mRotationItem ) { mRotationItem->setSymbolRotation( displayValue ); + setRotationPreviewBox( displayValue - mStartRotation ); mRotationItem->update(); } } @@ -117,9 +122,16 @@ void QgsMapToolRotateLabel::canvasMoveEvent( QMouseEvent * e ) void QgsMapToolRotateLabel::canvasReleaseEvent( QMouseEvent * e ) { + if ( !mLabelRubberBand ) //no rubber band created (most likely because the current label cannot be rotated ) + { + return; + } + deleteRubberBands(); delete mRotationItem; mRotationItem = 0; + delete mRotationPreviewBox; + mRotationPreviewBox = 0; QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID ); if ( !layer ) @@ -140,6 +152,10 @@ void QgsMapToolRotateLabel::canvasReleaseEvent( QMouseEvent * e ) } double rotation = mCtrlPressed ? roundTo15Degrees( mCurrentRotation ) : mCurrentRotation; + if ( rotation == mStartRotation ) //mouse button pressed / released, but no rotation + { + return; + } vlayer->beginEditCommand( tr( "Label rotated" ) ); vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rotationCol, rotation, false ); @@ -191,6 +207,16 @@ bool QgsMapToolRotateLabel::dataDefinedRotation( QgsVectorLayer* vlayer, int fea } QgsAttributeMap attributes = f.attributeMap(); + + //test, if data defined x- and y- values are not null. Otherwise, the position is determined by PAL and the rotation cannot be fixed + int xCol, yCol; + double x, y; + bool xSuccess, ySuccess; + if ( !dataDefinedPosition( vlayer, featureId, x, xSuccess, y, ySuccess, xCol, yCol ) || !xSuccess || !ySuccess ) + { + return false; + } + rotation = attributes[rotationCol].toDouble( &rotationSuccess ); return true; } @@ -205,3 +231,53 @@ double QgsMapToolRotateLabel::azimuthToCCW( double a ) { return ( a > 0 ? 360 - a : -a ); } + +QgsRubberBand* QgsMapToolRotateLabel::createRotationPreviewBox() +{ + delete mRotationPreviewBox; + QVector< QgsPoint > boxPoints = mCurrentLabelPos.cornerPoints; + if ( boxPoints.size() < 1 ) + { + return 0; + } + + mRotationPreviewBox = new QgsRubberBand( mCanvas, false ); + mRotationPreviewBox->setColor( Qt::blue ); + mRotationPreviewBox->setWidth( 3 ); + setRotationPreviewBox( mCurrentRotation - mStartRotation ); + return mRotationPreviewBox; +} + +void QgsMapToolRotateLabel::setRotationPreviewBox( double rotation ) +{ + if ( !mRotationPreviewBox ) + { + return; + } + + mRotationPreviewBox->reset(); + QVector< QgsPoint > boxPoints = mCurrentLabelPos.cornerPoints; + if ( boxPoints.size() < 1 ) + { + return; + } + + for ( int i = 0; i < boxPoints.size(); ++i ) + { + mRotationPreviewBox->addPoint( rotatePointCounterClockwise( boxPoints.at( i ), mRotationPoint, rotation ) ); + } + mRotationPreviewBox->addPoint( rotatePointCounterClockwise( boxPoints.at( 0 ), mRotationPoint, rotation ) ); + mRotationPreviewBox->show(); +} + +QgsPoint QgsMapToolRotateLabel::rotatePointCounterClockwise( const QgsPoint& input, const QgsPoint& centerPoint, double degrees ) +{ + double rad = degrees / 180 * M_PI; + double v1x = input.x() - centerPoint.x(); + double v1y = input.y() - centerPoint.y(); + + double v2x = cos( rad ) * v1x - sin( rad ) * v1y; + double v2y = sin( rad ) * v1x + cos( rad ) * v1y; + + return QgsPoint( centerPoint.x() + v2x, centerPoint.y() + v2y ); +} diff --git a/src/app/qgsmaptoolrotatelabel.h b/src/app/qgsmaptoolrotatelabel.h index ac6f1c2943e5..4a14156db2bb 100644 --- a/src/app/qgsmaptoolrotatelabel.h +++ b/src/app/qgsmaptoolrotatelabel.h @@ -49,11 +49,18 @@ class QgsMapToolRotateLabel: public QgsMapToolLabel /**Converts azimuth value to counterclockwise 0 - 360*/ static double azimuthToCCW( double a ); + QgsRubberBand* createRotationPreviewBox(); + void setRotationPreviewBox( double rotation ); + /**Rotates input point counterclockwise around centerPoint*/ + QgsPoint rotatePointCounterClockwise( const QgsPoint& input, const QgsPoint& centerPoint, double degrees ); + + double mStartRotation; //rotation value prior to start rotating double mCurrentRotation; double mCurrentMouseAzimuth; QgsPoint mRotationPoint; QgsPointRotationItem* mRotationItem; + QgsRubberBand* mRotationPreviewBox; /**True if ctrl was pressed during the last mouse move event*/ bool mCtrlPressed;