Skip to content

Commit

Permalink
[FEATURE]: add tool to graphically rotate points (by changing the val…
Browse files Browse the repository at this point in the history
…ue of the rotation field). Needs some more beautifying, perhaps a nicer arrow

git-svn-id: http://svn.osgeo.org/qgis/trunk@11671 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
mhugent committed Sep 16, 2009
1 parent 1669b15 commit 94e76d8
Show file tree
Hide file tree
Showing 8 changed files with 501 additions and 1 deletion.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -40,6 +40,7 @@ SET(QGIS_APP_SRCS
qgsmaptoolmovevertex.cpp
qgsmaptoolnodetool.cpp
qgsmaptoolreshape.cpp
qgsmaptoolrotatepointsymbols.cpp
qgsmaptoolselect.cpp
qgsmaptoolsimplify.cpp
qgsmaptoolsplitfeatures.cpp
Expand All @@ -52,6 +53,7 @@ SET(QGIS_APP_SRCS
qgsogrsublayersdialog.cpp
qgsoptions.cpp
qgspastetransformations.cpp
qgspointrotationitem.cpp
qgspluginitem.cpp
qgspluginmanager.cpp
qgspluginmetadata.cpp
Expand Down
30 changes: 29 additions & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -172,6 +172,7 @@
#include "qgsmaptoolpan.h"
#include "qgsmaptoolselect.h"
#include "qgsmaptoolreshape.h"
#include "qgsmaptoolrotatepointsymbols.h"
#include "qgsmaptoolsplitfeatures.h"
#include "qgsmaptoolvertexedit.h"
#include "qgsmaptoolzoom.h"
Expand Down Expand Up @@ -740,6 +741,12 @@ void QgisApp::createActions()
connect( mActionNodeTool, SIGNAL( triggered() ), this, SLOT( nodeTool() ) );
mActionNodeTool->setEnabled( false );

mActionRotatePointSymbols = new QAction( getThemeIcon( "mActionRotatePointSymbols.png" ), tr( "Rotate Point Symbols" ), this );
shortcuts->registerAction( mActionRotatePointSymbols );
mActionRotatePointSymbols->setStatusTip( tr( "Rotate Point Symbols" ) );
connect( mActionRotatePointSymbols, SIGNAL( triggered() ), this, SLOT( rotatePointSymbols() ) );
mActionRotatePointSymbols->setEnabled( false );

// View Menu Items

mActionPan = new QAction( getThemeIcon( "mActionPan.png" ), tr( "Pan Map" ), this );
Expand Down Expand Up @@ -1094,7 +1101,8 @@ void QgisApp::createActionGroups()
mMapToolGroup->addAction( mActionMergeFeatures );
mActionNodeTool->setCheckable( true );
mMapToolGroup->addAction( mActionNodeTool );

mActionRotatePointSymbols->setCheckable( true );
mMapToolGroup->addAction( mActionRotatePointSymbols );
}

void QgisApp::createMenus()
Expand Down Expand Up @@ -1189,6 +1197,7 @@ void QgisApp::createMenus()
mEditMenu->addAction( mActionSplitFeatures );
mEditMenu->addAction( mActionMergeFeatures );
mEditMenu->addAction( mActionNodeTool );
mEditMenu->addAction( mActionRotatePointSymbols );

if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
{
Expand Down Expand Up @@ -1398,6 +1407,7 @@ void QgisApp::createToolBars()
mAdvancedDigitizeToolBar->addAction( mActionSplitFeatures );
mAdvancedDigitizeToolBar->addAction( mActionMergeFeatures );
mAdvancedDigitizeToolBar->addAction( mActionNodeTool );
mAdvancedDigitizeToolBar->addAction( mActionRotatePointSymbols );
mToolbarMenu->addAction( mAdvancedDigitizeToolBar->toggleViewAction() );


Expand Down Expand Up @@ -1788,6 +1798,8 @@ void QgisApp::createCanvas()
mMapTools.mDeletePart->setAction( mActionDeletePart );
mMapTools.mNodeTool = new QgsMapToolNodeTool( mMapCanvas );
mMapTools.mNodeTool->setAction( mActionNodeTool );
mMapTools.mRotatePointSymbolsTool = new QgsMapToolRotatePointSymbols( mMapCanvas );
mMapTools.mRotatePointSymbolsTool->setAction( mActionRotatePointSymbols );
//ensure that non edit tool is initialised or we will get crashes in some situations
mNonEditMapTool = mMapTools.mPan;
}
Expand Down Expand Up @@ -4298,6 +4310,11 @@ void QgisApp::nodeTool()
mMapCanvas->setMapTool( mMapTools.mNodeTool );
}

void QgisApp::rotatePointSymbols()
{
mMapCanvas->setMapTool( mMapTools.mRotatePointSymbolsTool );
}

void QgisApp::splitFeatures()
{
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
Expand Down Expand Up @@ -5639,11 +5656,19 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionSplitFeatures->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionDeleteRing->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );

if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
mActionMoveVertex->setEnabled( true );
}
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues )
{
if ( QgsMapToolRotatePointSymbols::layerIsRotatable( vlayer ) )
{
mActionRotatePointSymbols->setEnabled( true );
}
}
return;
}
else if ( vlayer->geometryType() == QGis::Line )
Expand Down Expand Up @@ -5752,6 +5777,9 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionCopyFeatures->setEnabled( false );
mActionCutFeatures->setEnabled( false );
mActionPasteFeatures->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );
mActionNodeTool->setEnabled( false );
mActionDeletePart->setEnabled( false );

//NOTE: This check does not really add any protection, as it is called on load not on layer select/activate
//If you load a layer with a provider and idenitfy ability then load another without, the tool would be disabled for both
Expand Down
4 changes: 4 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -523,6 +523,8 @@ class QgisApp : public QMainWindow
void mergeSelectedFeatures();
//! provides operations with nodes
void nodeTool();
//! activates the rotate points tool
void rotatePointSymbols();

//! activates the selection tool
void select();
Expand Down Expand Up @@ -742,6 +744,7 @@ class QgisApp : public QMainWindow
QAction *mActionDeletePart;
QAction *mActionMergeFeatures;
QAction *mActionNodeTool;
QAction *mActionRotatePointSymbols;
QAction *mActionEditSeparator3;

QAction *mActionPan;
Expand Down Expand Up @@ -864,6 +867,7 @@ class QgisApp : public QMainWindow
QgsMapTool* mDeleteRing;
QgsMapTool* mDeletePart;
QgsMapTool* mNodeTool;
QgsMapTool* mRotatePointSymbolsTool;
} mMapTools;

QgsMapTool *mNonEditMapTool;
Expand Down
250 changes: 250 additions & 0 deletions src/app/qgsmaptoolrotatepointsymbols.cpp
@@ -0,0 +1,250 @@
/***************************************************************************
qgsmaptoolrotatepointsymbols.cpp
--------------------------------
begin : September 2009
copyright : (C) 2009 by Marco Hugentobler
email : marco at hugis dot net
***************************************************************************
* *
* 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 "qgsmaptoolrotatepointsymbols.h"
#include "qgsapplication.h"
#include "qgsmapcanvas.h"
#include "qgspointrotationitem.h"
#include "qgsrenderer.h"
#include "qgssymbol.h"
#include "qgsvectorlayer.h"
#include <QGraphicsPixmapItem>
#include <QMessageBox>
#include <QMouseEvent>

QgsMapToolRotatePointSymbols::QgsMapToolRotatePointSymbols( QgsMapCanvas* canvas ): QgsMapToolEdit( canvas ), \
mActiveLayer( 0 ), mFeatureNumber( 0 ), mCurrentMouseAzimut( 0.0 ), mCurrentRotationFeature( 0.0 ), mRotating( false ), mRotationItem( 0 )
{

}

QgsMapToolRotatePointSymbols::~QgsMapToolRotatePointSymbols()
{
delete mRotationItem;
}

bool QgsMapToolRotatePointSymbols::layerIsRotatable( QgsMapLayer* ml )
{
if ( !ml )
{
return false;
}

//a vector layer
QgsVectorLayer* vLayer = dynamic_cast<QgsVectorLayer*>( ml );
if ( !vLayer )
{
return false;
}

//does it have point or multipoint type?
if ( vLayer->geometryType() != QGis::Point )
{
return false;
}

//does it have a least one rotation attribute?
QList<int> rotationAttributes;
layerRotationAttributes( vLayer, rotationAttributes );
if ( rotationAttributes.size() < 1 )
{
return false;
}
return true;
}

void QgsMapToolRotatePointSymbols::canvasPressEvent( QMouseEvent * e )
{
if ( !mCanvas )
{
return;
}

mActiveLayer = currentVectorLayer();
if ( !mActiveLayer )
{
return;
}

if ( mActiveLayer->geometryType() != QGis::Point || !mActiveLayer->isEditable() )
{
return;
}

//find the closest feature to the pressed position
QgsMapCanvasSnapper canvasSnapper( mCanvas );
QList<QgsSnappingResult> snapResults;
if ( canvasSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex, -1 ) != 0 || snapResults.size() < 1 )
{
QMessageBox::critical( 0, tr( "No point feature" ), tr( "No point feature was detected at the clicked position. Please click closer to the feature or enhance the search tolerance under Settings->Options->Digitizing->Serch radius for vertex edits" ) );
return; //error during snapping
}

mFeatureNumber = snapResults.at( 0 ).snappedAtGeometry;

//get list with renderer rotation attributes
if ( layerRotationAttributes( mActiveLayer, mCurrentRotationAttributes ) != 0 )
{
return;
}

if ( mCurrentRotationAttributes.size() < 1 )
{
QMessageBox::critical( 0, tr( "No rotation Attributes" ), tr( "The active point layer does not have a rotation attribute" ) );
return;
}

mSnappedPoint = toCanvasCoordinates( snapResults.at( 0 ).snappedVertex );

//find out initial arrow direction
QgsFeature pointFeature;
if ( !mActiveLayer->featureAtId( mFeatureNumber, pointFeature, false, true ) )
{
return;
}
const QgsAttributeMap pointFeatureAttributes = pointFeature.attributeMap();
const QgsAttributeMap::const_iterator attIt = pointFeatureAttributes.find( mCurrentRotationAttributes.at( 0 ) );
if ( attIt == pointFeatureAttributes.constEnd() )
{
return;
}

mCurrentRotationFeature = attIt.value().toDouble();
createPixmapItem();
if ( mRotationItem )
{
mRotationItem->setPointLocation( snapResults.at( 0 ).snappedVertex );
}
mCurrentMouseAzimut = calculateAzimut( e->pos() );
setPixmapItemRotation( mCurrentMouseAzimut );
mRotating = true;
}

void QgsMapToolRotatePointSymbols::canvasMoveEvent( QMouseEvent * e )
{
if ( !mRotating )
{
return;
}

double azimut = calculateAzimut( e->pos() );
double azimutDiff = azimut - mCurrentMouseAzimut;

//assign new feature rotation, making sure to respect the 0 - 360 degree range
mCurrentRotationFeature += azimutDiff;
if ( mCurrentRotationFeature < 0 )
{
mCurrentRotationFeature = 360 - mCurrentRotationFeature;
}
else if ( mCurrentRotationFeature >= 360 )
{
mCurrentRotationFeature -= 360;
}
mCurrentMouseAzimut = azimut;
if ( mCurrentMouseAzimut < 0 )
{
mCurrentMouseAzimut = 360 - mCurrentMouseAzimut;
}
else if ( mCurrentMouseAzimut >= 360 )
{
mCurrentMouseAzimut -= 360;
}
setPixmapItemRotation( mCurrentRotationFeature );
}

void QgsMapToolRotatePointSymbols::canvasReleaseEvent( QMouseEvent * e )
{
if ( mRotating && mActiveLayer )
{
mActiveLayer->beginEditCommand( tr( "Rotate symbol" ) );
bool rotateSuccess = true;

//write mCurrentRotationFeature to all rotation attributes of feature (mFeatureNumber)
QList<int>::const_iterator it = mCurrentRotationAttributes.constBegin();
for ( ; it != mCurrentRotationAttributes.constEnd(); ++it )
{
if ( !mActiveLayer->changeAttributeValue( mFeatureNumber, *it, mCurrentRotationFeature, true ) )
{
rotateSuccess = false;
}
}

if ( rotateSuccess )
{
mActiveLayer->endEditCommand();
}
else
{
mActiveLayer->destroyEditCommand();
}
}
mRotating = false;
delete mRotationItem;
mRotationItem = 0;
mCanvas->refresh();
}

int QgsMapToolRotatePointSymbols::layerRotationAttributes( const QgsVectorLayer* vl, QList<int>& attList )
{
attList.clear();
if ( !vl )
{
return 1;
}

//get renderer
const QgsRenderer* layerRenderer = vl->renderer();
if ( !layerRenderer )
{
return 2;
}

//get renderer symbols
const QList<QgsSymbol*> rendererSymbols = layerRenderer->symbols();
int currentRotationAttribute;

QList<QgsSymbol*>::const_iterator symbolIt = rendererSymbols.constBegin();
for ( ; symbolIt != rendererSymbols.constEnd(); ++symbolIt )
{
currentRotationAttribute = ( *symbolIt )->rotationClassificationField();
if ( currentRotationAttribute >= 0 )
{
attList.push_back( currentRotationAttribute );
}
}
return 0;
}

double QgsMapToolRotatePointSymbols::calculateAzimut( const QPoint& mousePos )
{
int dx = mousePos.x() - mSnappedPoint.x();
int dy = mousePos.y() - mSnappedPoint.y();
return 180 - atan2( dx, dy ) * 180.0 / M_PI;
}

void QgsMapToolRotatePointSymbols::createPixmapItem()
{
delete mRotationItem;
mRotationItem = new QgsPointRotationItem( mCanvas );
mRotationItem->setSymbol( QgsApplication::defaultThemePath() + "mActionArrowUp.png" );
mCanvas->scene()->addItem( mRotationItem );
}

void QgsMapToolRotatePointSymbols::setPixmapItemRotation( double rotation )
{
mRotationItem->setSymbolRotation( rotation );
mRotationItem->update();
}

0 comments on commit 94e76d8

Please sign in to comment.