Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Improve point rotation tool support for renderers to allow use
with rule based renderer

fixes #12917, #12123 and refs #5001
  • Loading branch information
nyalldawson committed Aug 6, 2015
1 parent 9c3d65e commit 933069d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 70 deletions.
120 changes: 56 additions & 64 deletions src/app/qgsmaptoolrotatepointsymbols.cpp
Expand Up @@ -57,13 +57,8 @@ bool QgsMapToolRotatePointSymbols::layerIsRotatable( QgsMapLayer* ml )
return false;
}

//does it have a least one rotation attribute?
QList<int> rotationAttributes;
layerRotationAttributes( vLayer, rotationAttributes );
if ( rotationAttributes.size() < 1 )
{
return false;
}
//we consider all point layers as rotatable, as data defined rotation can be set on a per
//symbol/feature basis
return true;
}

Expand Down Expand Up @@ -101,35 +96,71 @@ void QgsMapToolRotatePointSymbols::canvasPressEvent( QMouseEvent *e )
}

mFeatureNumber = m.featureId();
mCurrentRotationAttributes.clear();
mSnappedPoint = toCanvasCoordinates( m.point() );

//get list with renderer rotation attributes
if ( layerRotationAttributes( mActiveLayer, mCurrentRotationAttributes ) != 0 )
QgsFeature pointFeature;
if ( !mActiveLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setFilterFid( mFeatureNumber ) ).nextFeature( pointFeature ) )
{
return;
}

if ( mCurrentRotationAttributes.size() < 1 )
{
emit messageEmitted( tr( "The active point layer does not have a rotation attribute." ), QgsMessageBar::CRITICAL );
//check whether selected feature has a rotatable symbol
QgsFeatureRendererV2* renderer = mActiveLayer->rendererV2();
if ( !renderer )
return;
}
QgsRenderContext context = QgsRenderContext::fromMapSettings( mCanvas->mapSettings() );
renderer->startRender( context, mActiveLayer->fields() );

mSnappedPoint = toCanvasCoordinates( m.point() );
//find all rotation fields used by renderer for feature
QgsMarkerSymbolV2* markerSymbol = 0;
if ( renderer->capabilities() & QgsFeatureRendererV2::MoreSymbolsPerFeature )
{
//could be multiple symbols for this feature, so check them all
foreach ( QgsSymbolV2* s, renderer->originalSymbolsForFeature( pointFeature ) )
{
if ( s && s->type() == QgsSymbolV2::Marker )
{
markerSymbol = static_cast< QgsMarkerSymbolV2* >( s );
QString rotationField = ( markerSymbol->dataDefinedAngle().isActive() && !markerSymbol->dataDefinedAngle().useExpression() ) ?
markerSymbol->dataDefinedAngle().field() : QString();
if ( !rotationField.isEmpty() )
{
int fieldIndex = mActiveLayer->fields().indexFromName( rotationField );
if ( !mCurrentRotationAttributes.contains( fieldIndex ) )
mCurrentRotationAttributes << fieldIndex;
}
}
}
}
else
{
QgsSymbolV2* s = renderer->originalSymbolForFeature( pointFeature );
if ( s && s->type() == QgsSymbolV2::Marker )
{
markerSymbol = static_cast< QgsMarkerSymbolV2* >( s );
QString rotationField = ( markerSymbol->dataDefinedAngle().isActive() && !markerSymbol->dataDefinedAngle().useExpression() ) ?
markerSymbol->dataDefinedAngle().field() : QString();
if ( !rotationField.isEmpty() )
mCurrentRotationAttributes << mActiveLayer->fields().indexFromName( rotationField );
}
}

//find out initial arrow direction
QgsFeature pointFeature;
if ( !mActiveLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setFilterFid( mFeatureNumber ) ).nextFeature( pointFeature ) )
if ( mCurrentRotationAttributes.isEmpty() )
{
emit messageEmitted( tr( "The selected point does not have a rotation attribute." ), QgsMessageBar::CRITICAL );
return;
}

//find out initial arrow direction
QVariant attrVal = pointFeature.attribute( mCurrentRotationAttributes.at( 0 ) );
if ( !attrVal.isValid() )
{
return;
}

mCurrentRotationFeature = attrVal.toDouble();
createPixmapItem( pointFeature );
createPixmapItem( markerSymbol );
if ( mRotationItem )
{
mRotationItem->setPointLocation( m.point() );
Expand Down Expand Up @@ -228,69 +259,30 @@ void QgsMapToolRotatePointSymbols::canvasReleaseEvent( QMouseEvent *e )
mCanvas->refresh();
}

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

//new symbology
const QgsFeatureRendererV2* symbologyNgRenderer = vl->rendererV2();
if ( symbologyNgRenderer )
{
//TODO - replace this method with code which handles data defined rotation on the symbol level
Q_NOWARN_DEPRECATED_PUSH
QString rotationFieldName = symbologyNgRenderer->rotationField();
Q_NOWARN_DEPRECATED_POP

if ( !rotationFieldName.isEmpty() )
{
attList.push_back( vl->fieldNameIndex( rotationFieldName ) );
}
return 0;
}

//no renderer
return 2;
}



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

void QgsMapToolRotatePointSymbols::createPixmapItem( QgsFeature& f )
void QgsMapToolRotatePointSymbols::createPixmapItem( QgsMarkerSymbolV2* markerSymbol )
{
if ( !mCanvas )
{
return;
}

QgsRenderContext renderContext( QgsRenderContext::fromMapSettings( mCanvas->mapSettings() ) );

//get the image that is used for that symbol, but without point rotation
QImage pointImage;

if ( mActiveLayer && mActiveLayer->rendererV2() ) //symbology-ng
if ( markerSymbol )
{
QgsFeatureRendererV2* rv2 = mActiveLayer->rendererV2()->clone();
rv2->startRender( renderContext, mActiveLayer->fields() );

QgsSymbolV2* symbolV2 = rv2->symbolForFeature( f );
if ( symbolV2 && symbolV2->type() == QgsSymbolV2::Marker )
{
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbolV2 );
markerSymbol->setDataDefinedAngle( QgsDataDefined() );
pointImage = markerSymbol->bigSymbolPreviewImage();
}
rv2->stopRender( renderContext );
delete rv2;
QgsSymbolV2* clone = markerSymbol->clone();
QgsMarkerSymbolV2* markerClone = static_cast<QgsMarkerSymbolV2*>( clone );
markerClone->setDataDefinedAngle( QgsDataDefined() );
pointImage = markerClone->bigSymbolPreviewImage();
delete clone;
}

mRotationItem = new QgsPointRotationItem( mCanvas );
Expand Down
8 changes: 2 additions & 6 deletions src/app/qgsmaptoolrotatepointsymbols.h
Expand Up @@ -20,6 +20,7 @@
#include "qgsfeature.h"

class QgsPointRotationItem;
class QgsMarkerSymbolV2;

/** A class that allows interactive manipulation the value of the rotation field(s) for point layers*/
class APP_EXPORT QgsMapToolRotatePointSymbols: public QgsMapToolEdit
Expand Down Expand Up @@ -56,16 +57,11 @@ class APP_EXPORT QgsMapToolRotatePointSymbols: public QgsMapToolEdit
/** True if ctrl was pressed during the last mouse move event*/
bool mCtrlPressed;

/** Finds out the rotation attributes of mActiveLayers
@param vl the point vector layer
@param attList out: the list containing the rotation indices
@return 0 in case of success*/
static int layerRotationAttributes( QgsVectorLayer* vl, QList<int>& attList );
void drawArrow( double azimut ) const;
/** Calculates the azimut between mousePos and mSnappedPoint*/
double calculateAzimut( const QPoint& mousePos );
/** Create item with the point symbol for a specific feature. This will be used to show the rotation to the user*/
void createPixmapItem( QgsFeature& f );
void createPixmapItem( QgsMarkerSymbolV2 *markerSymbol );
/** Sets the rotation of the pixmap item*/
void setPixmapItemRotation( double rotation );
/** Rounds value to 15 degree integer (used if ctrl pressed)*/
Expand Down

0 comments on commit 933069d

Please sign in to comment.