8 changes: 4 additions & 4 deletions src/app/composer/qgscomposershapewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void QgsComposerShapeWidget::setGuiElementValues()

blockAllSignals( true );

mRotationSpinBox->setValue( mComposerShape->rotation() );
mRotationSpinBox->setValue( mComposerShape->itemRotation() );
mCornerRadiusSpinBox->setValue( mComposerShape->cornerRadius() );
if ( mComposerShape->shapeType() == QgsComposerShape::Ellipse )
{
Expand All @@ -91,8 +91,8 @@ void QgsComposerShapeWidget::on_mRotationSpinBox_valueChanged( int val )
{
if ( mComposerShape )
{
mComposerShape->beginCommand( tr( "Shape rotation changed" ), QgsComposerMergeCommand::ShapeRotation );
mComposerShape->setRotation( val );
mComposerShape->beginCommand( tr( "Shape rotation changed" ), QgsComposerMergeCommand::ItemRotation );
mComposerShape->setItemRotation( val );
mComposerShape->update();
mComposerShape->endCommand();
}
Expand All @@ -102,7 +102,7 @@ void QgsComposerShapeWidget::on_mCornerRadiusSpinBox_valueChanged( double val )
{
if ( mComposerShape )
{
mComposerShape->beginCommand( tr( "Shape radius changed" ), QgsComposerMergeCommand::ShapeRotation );
mComposerShape->beginCommand( tr( "Shape radius changed" ), QgsComposerMergeCommand::ShapeCornerRadius );
mComposerShape->setCornerRadius( val );
mComposerShape->update();
mComposerShape->endCommand();
Expand Down
58 changes: 43 additions & 15 deletions src/core/composer/qgscomposeritem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ QgsComposerItem::QgsComposerItem( QgsComposition* composition, bool manageZValue
, mBackgroundColor( QColor( 255, 255, 255, 255 ) )
, mItemPositionLocked( false )
, mLastValidViewScaleFactor( -1 )
, mRotation( 0 )
, mItemRotation( 0 )
, mBlendMode( QPainter::CompositionMode_SourceOver )
, mEffectsEnabled( true )
, mTransparency( 0 )
Expand All @@ -77,7 +77,7 @@ QgsComposerItem::QgsComposerItem( qreal x, qreal y, qreal width, qreal height, Q
, mBackgroundColor( QColor( 255, 255, 255, 255 ) )
, mItemPositionLocked( false )
, mLastValidViewScaleFactor( -1 )
, mRotation( 0 )
, mItemRotation( 0 )
, mBlendMode( QPainter::CompositionMode_SourceOver )
, mEffectsEnabled( true )
, mTransparency( 0 )
Expand Down Expand Up @@ -170,7 +170,7 @@ bool QgsComposerItem::_writeXML( QDomElement& itemElem, QDomDocument& doc ) cons
composerItemElem.setAttribute( "positionMode", QString::number(( int ) mLastUsedPositionMode ) );
composerItemElem.setAttribute( "zValue", QString::number( zValue() ) );
composerItemElem.setAttribute( "outlineWidth", QString::number( pen().widthF() ) );
composerItemElem.setAttribute( "rotation", QString::number( mRotation ) );
composerItemElem.setAttribute( "itemRotation", QString::number( mItemRotation ) );
composerItemElem.setAttribute( "uuid", mUuid );
composerItemElem.setAttribute( "id", mId );
//position lock for mouse moves/resizes
Expand Down Expand Up @@ -224,7 +224,10 @@ bool QgsComposerItem::_readXML( const QDomElement& itemElem, const QDomDocument&
}

//rotation
mRotation = itemElem.attribute( "rotation", "0" ).toDouble();
if ( itemElem.attribute( "itemRotation", "0" ).toDouble() != 0 )
{
mItemRotation = itemElem.attribute( "itemRotation", "0" ).toDouble();
}

//uuid
mUuid = itemElem.attribute( "uuid", QUuid::createUuid().toString() );
Expand Down Expand Up @@ -697,27 +700,40 @@ double QgsComposerItem::lockSymbolSize() const
}

void QgsComposerItem::setRotation( double r )
{
//kept for api compatibility with QGIS 2.0
//remove after 2.0 series
setItemRotation( r );
}

void QgsComposerItem::setItemRotation( double r )
{
if ( r > 360 )
{
mRotation = (( int )r ) % 360;
mItemRotation = (( int )r ) % 360;
}
else
{
mRotation = r;
mItemRotation = r;
}
emit rotationChanged( r );
emit itemRotationChanged( r );
update();
}

bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height ) const
{
if ( qAbs( mRotation ) <= 0.0 ) //width and height stays the same if there is no rotation
//kept for api compatibility with QGIS 2.0, use item rotation
return imageSizeConsideringRotation( width, height, mItemRotation );
}

bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation ) const
{
if ( qAbs( rotation ) <= 0.0 ) //width and height stays the same if there is no rotation
{
return true;
}

if ( qgsDoubleNear( qAbs( mRotation ), 90 ) || qgsDoubleNear( qAbs( mRotation ), 270 ) )
if ( qgsDoubleNear( qAbs( rotation ), 90 ) || qgsDoubleNear( qAbs( rotation ), 270 ) )
{
double tmp = width;
width = height;
Expand Down Expand Up @@ -775,9 +791,15 @@ bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& heigh
}

bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
{
//kept for api compatibility with QGIS 2.0, use item rotation
return cornerPointOnRotatedAndScaledRect( x, y, width, height, mItemRotation );
}

bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) const
{
//first rotate point clockwise
double rotToRad = mRotation * M_PI / 180.0;
double rotToRad = rotation * M_PI / 180.0;
QPointF midpoint( width / 2.0, height / 2.0 );
double xVector = x - midpoint.x();
double yVector = y - midpoint.y();
Expand Down Expand Up @@ -813,27 +835,33 @@ bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, d

void QgsComposerItem::sizeChangedByRotation( double& width, double& height )
{
if ( mRotation == 0.0 )
//kept for api compatibility with QGIS 2.0, use item rotation
return sizeChangedByRotation( width, height, mItemRotation );
}

void QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation )
{
if ( rotation == 0.0 )
{
return;
}

//vector to p1
double x1 = -width / 2.0;
double y1 = -height / 2.0;
rotate( mRotation, x1, y1 );
rotate( rotation, x1, y1 );
//vector to p2
double x2 = width / 2.0;
double y2 = -height / 2.0;
rotate( mRotation, x2, y2 );
rotate( rotation, x2, y2 );
//vector to p3
double x3 = width / 2.0;
double y3 = height / 2.0;
rotate( mRotation, x3, y3 );
rotate( rotation, x3, y3 );
//vector to p4
double x4 = -width / 2.0;
double y4 = height / 2.0;
rotate( mRotation, x4, y4 );
rotate( rotation, x4, y4 );

//double midpoint
QPointF midpoint( width / 2.0, height / 2.0 );
Expand Down
44 changes: 39 additions & 5 deletions src/core/composer/qgscomposeritem.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,15 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
@note this method was added in version 1.2*/
bool positionLock() const {return mItemPositionLocked;}

double rotation() const {return mRotation;}
/**Returns the rotation for the composer item
@note this method was added in version 2.1*/
double itemRotation() const {return mItemRotation;}

/**Returns the rotation for the composer item
* @deprecated Use itemRotation()
* instead
*/
double rotation() const {return mItemRotation;}

/**Updates item, with the possibility to do custom update for subclasses*/
virtual void updateItem() { QGraphicsRectItem::update(); }
Expand All @@ -306,7 +314,16 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
QString uuid() const { return mUuid; }

public slots:
/**Sets the item rotation
* @deprecated Use setItemRotation( double rotation ) instead
*/
virtual void setRotation( double r );

/**Sets the item rotation
@note this method was added in version 2.1
*/
virtual void setItemRotation( double r );

void repaint();

protected:
Expand Down Expand Up @@ -339,7 +356,7 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
mutable double mLastValidViewScaleFactor;

/**Item rotation in degrees, clockwise*/
double mRotation;
double mItemRotation;

/**Composition blend mode for item*/
QPainter::CompositionMode mBlendMode;
Expand Down Expand Up @@ -384,12 +401,29 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
//some utility functions

/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation*/
bool imageSizeConsideringRotation( double& width, double& height, double rotation ) const;
/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation
* @deprecated Use bool imageSizeConsideringRotation( double& width, double& height, double rotation )
* instead
*/
bool imageSizeConsideringRotation( double& width, double& height ) const;

/**Calculates corner point after rotation and scaling*/
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) const;
/**Calculates corner point after rotation and scaling
* @deprecated Use bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation )
* instead
*/
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const;

/**Calculates width / height of the bounding box of a rotated rectangle (mRotation)*/
/**Calculates width / height of the bounding box of a rotated rectangle*/
void sizeChangedByRotation( double& width, double& height, double rotation );
/**Calculates width / height of the bounding box of a rotated rectangle
* @deprecated Use void sizeChangedByRotation( double& width, double& height, double rotation )
* instead
*/
void sizeChangedByRotation( double& width, double& height );

/**Rotates a point / vector
@param angle rotation angle in degrees, counterclockwise
@param x in/out: x coordinate before / after the rotation
Expand All @@ -405,8 +439,8 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
void deleteAlignItems();

signals:
/**Is emitted on rotation change to notify north arrow pictures*/
void rotationChanged( double newRotation );
/**Is emitted on item rotation change*/
void itemRotationChanged( double newRotation );
/**Used e.g. by the item widgets to update the gui elements*/
void itemChanged();
/**Emitted if the rectangle changes*/
Expand Down
6 changes: 3 additions & 3 deletions src/core/composer/qgscomposeritemcommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
//composer label
ComposerLabelSetText,
ComposerLabelSetId,
ComposerLabelRotation,
//composer map
ComposerMapRotation,
ComposerMapAnnotationDistance,
Expand Down Expand Up @@ -111,14 +110,15 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
TableMargin,
TableGridStrokeWidth,
//composer shape
ShapeRotation,
ShapeCornerRadius,
ShapeOutlineWidth,
//composer arrow
ArrowOutlineWidth,
ArrowHeadWidth,
//item
ItemOutlineWidth,
ItemMove
ItemMove,
ItemRotation
};

QgsComposerMergeCommand( Context c, QgsComposerItem* item, const QString& text );
Expand Down
26 changes: 20 additions & 6 deletions src/core/composer/qgscomposerlabel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
double penWidth = pen().widthF();
QRectF painterRect( penWidth + mMargin, penWidth + mMargin, mTextBoxWidth - 2 * penWidth - 2 * mMargin, mTextBoxHeight - 2 * penWidth - 2 * mMargin );
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
painter->rotate( mRotation );
painter->rotate( mItemRotation );
painter->translate( -mTextBoxWidth / 2.0, -mTextBoxHeight / 2.0 );

if ( mHtmlState )
Expand Down Expand Up @@ -246,10 +246,16 @@ QFont QgsComposerLabel::font() const
}

void QgsComposerLabel::setRotation( double r )
{
//kept for api compatibility with QGIS 2.0
setItemRotation( r );
}

void QgsComposerLabel::setItemRotation( double r )
{
double width = mTextBoxWidth;
double height = mTextBoxHeight;
QgsComposerItem::setRotation( r );
QgsComposerItem::setItemRotation( r );
sizeChangedByRotation( width, height );

double x = pos().x() + rect().width() / 2.0 - width / 2.0;
Expand Down Expand Up @@ -359,6 +365,14 @@ bool QgsComposerLabel::readXML( const QDomElement& itemElem, const QDomDocument&
if ( composerItemList.size() > 0 )
{
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();

//rotation
if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
{
//check for old (pre 2.1) rotation attribute
mItemRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
}

_readXML( composerItemElem, doc );
}
emit itemChanged();
Expand All @@ -373,7 +387,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d
xShift = 0;
yShift = 0;

if ( mRotation >= 0 && mRotation < 90 )
if ( mItemRotation >= 0 && mItemRotation < 90 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
Expand All @@ -392,7 +406,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d
yShift = - ( newHeight - currentHeight );
}
}
if ( mRotation >= 90 && mRotation < 180 )
if ( mItemRotation >= 90 && mItemRotation < 180 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
Expand All @@ -411,7 +425,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d
xShift = -( newWidth - currentWidth / 2.0 );
}
}
else if ( mRotation >= 180 && mRotation < 270 )
else if ( mItemRotation >= 180 && mItemRotation < 270 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
Expand All @@ -430,7 +444,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d
yShift = ( newHeight - currentHeight );
}
}
else if ( mRotation >= 270 && mRotation < 360 )
else if ( mItemRotation >= 270 && mItemRotation < 360 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
Expand Down
6 changes: 6 additions & 0 deletions src/core/composer/qgscomposerlabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,14 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );

public slots:
/* Sets rotation for the label
* @deprecated Use setItemRotation( double rotation ) instead
*/
virtual void setRotation( double r );

/* Sets rotation for the label */
virtual void setItemRotation( double r );

private slots:
void loadingHtmlFinished( bool );

Expand Down
73 changes: 57 additions & 16 deletions src/core/composer/qgscomposermap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#include <cmath>

QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
: QgsComposerItem( x, y, width, height, composition ), mKeepLayerSet( false ),
: QgsComposerItem( x, y, width, height, composition ), mMapRotation( 0 ), mKeepLayerSet( false ),
mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false ),
mGridEnabled( false ), mGridStyle( Solid ),
mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ),
Expand Down Expand Up @@ -98,7 +98,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w
}

QgsComposerMap::QgsComposerMap( QgsComposition *composition )
: QgsComposerItem( 0, 0, 10, 10, composition ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ),
: QgsComposerItem( 0, 0, 10, 10, composition ), mMapRotation( 0 ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ),
mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false ),
mGridEnabled( false ), mGridStyle( Solid ),
mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ),
Expand Down Expand Up @@ -385,7 +385,7 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i

painter->translate( mXOffset, mYOffset );
painter->translate( xTopLeftShift, yTopLeftShift );
painter->rotate( mRotation );
painter->rotate( mMapRotation );
painter->translate( xShiftMM, -yShiftMM );
painter->scale( scale, scale );
painter->drawImage( 0, 0, mCacheImage );
Expand Down Expand Up @@ -434,7 +434,7 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i
painter->save();
painter->translate( mXOffset, mYOffset );
painter->translate( xTopLeftShift, yTopLeftShift );
painter->rotate( mRotation );
painter->rotate( mMapRotation );
painter->translate( xShiftMM, -yShiftMM );
draw( painter, requestRectangle, theSize, 25.4 ); //scene coordinates seem to be in mm

Expand Down Expand Up @@ -654,11 +654,18 @@ void QgsComposerMap::setOffset( double xOffset, double yOffset )
mYOffset = yOffset;
}

void QgsComposerMap::setRotation( double r )
{
//kept for api compatibility with QGIS 2.0
setMapRotation( r );
}

void QgsComposerMap::setMapRotation( double r )
{
setRotation( r );
emit rotationChanged( r );
mMapRotation = r;
emit mapRotationChanged( r );
emit itemChanged();
update();
}

void QgsComposerMap::updateItem()
Expand Down Expand Up @@ -842,6 +849,9 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) );
composerMapElem.appendChild( extentElem );

//map rotation
composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) );

//layer set
QDomElement layerSetElem = doc.createElement( "LayerSet" );
QStringList::const_iterator layerIt = mLayerSet.constBegin();
Expand Down Expand Up @@ -1000,6 +1010,12 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d
mExtent = QgsRectangle( xmin, ymin, xmax, ymax );
}

//map rotation
if ( itemElem.attribute( "mapRotation", "0" ).toDouble() != 0 )
{
mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble();
}

//mKeepLayerSet flag
QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
Expand Down Expand Up @@ -1161,6 +1177,13 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d
if ( composerItemList.size() > 0 )
{
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();

if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
{
//in versions prior to 2.1 map rotation was stored in the rotation attribute
mMapRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
}

_readXML( composerItemElem, doc );
}

Expand Down Expand Up @@ -1637,7 +1660,7 @@ int QgsComposerMap::xGridLines( QList< QPair< double, QLineF > >& lines ) const
double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
double currentLevel = ( int )(( mapBoundingRect.top() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;

if ( qgsDoubleNear( mRotation, 0.0 ) )
if ( qgsDoubleNear( mMapRotation, 0.0 ) )
{
//no rotation. Do it 'the easy way'

Expand Down Expand Up @@ -1705,7 +1728,7 @@ int QgsComposerMap::yGridLines( QList< QPair< double, QLineF > >& lines ) const
double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
double currentLevel = ( int )(( mapBoundingRect.left() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;

if ( qgsDoubleNear( mRotation, 0.0 ) )
if ( qgsDoubleNear( mMapRotation, 0.0 ) )
{
//no rotation. Do it 'the easy way'
double xCanvasCoord;
Expand Down Expand Up @@ -1888,7 +1911,7 @@ double QgsComposerMap::maxExtension() const
void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const
{
poly.clear();
if ( mRotation == 0 )
if ( mMapRotation == 0 )
{
poly << QPointF( extent.xMinimum(), extent.yMaximum() );
poly << QPointF( extent.xMaximum(), extent.yMaximum() );
Expand All @@ -1904,25 +1927,25 @@ void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) c
//top left point
dx = rotationPoint.x() - extent.xMinimum();
dy = rotationPoint.y() - extent.yMaximum();
rotate( mRotation, dx, dy );
rotate( mMapRotation, dx, dy );
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );

//top right point
dx = rotationPoint.x() - extent.xMaximum();
dy = rotationPoint.y() - extent.yMaximum();
rotate( mRotation, dx, dy );
rotate( mMapRotation, dx, dy );
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );

//bottom right point
dx = rotationPoint.x() - extent.xMaximum();
dy = rotationPoint.y() - extent.yMinimum();
rotate( mRotation, dx, dy );
rotate( mMapRotation, dx, dy );
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );

//bottom left point
dx = rotationPoint.x() - extent.xMinimum();
dy = rotationPoint.y() - extent.yMinimum();
rotate( mRotation, dx, dy );
rotate( mMapRotation, dx, dy );
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
}

Expand All @@ -1935,7 +1958,7 @@ void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const
{
QgsRectangle newExtent;
extentCenteredOnOverview( newExtent );
if ( mRotation == 0 )
if ( mMapRotation == 0 )
{
extent = newExtent;
}
Expand Down Expand Up @@ -2019,7 +2042,7 @@ void QgsComposerMap::transformShift( double& xShift, double& yShift ) const
double dxScaled = xShift * mmToMapUnits;
double dyScaled = - yShift * mmToMapUnits;

rotate( mRotation, dxScaled, dyScaled );
rotate( mMapRotation, dxScaled, dyScaled );

xShift = dxScaled;
yShift = dyScaled;
Expand All @@ -2037,7 +2060,7 @@ QPointF QgsComposerMap::mapToItemCoords( const QPointF& mapCoords ) const
QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
double dx = mapCoords.x() - rotationPoint.x();
double dy = mapCoords.y() - rotationPoint.y();
rotate( -mRotation, dx, dy );
rotate( -mMapRotation, dx, dy );
QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );

QgsRectangle unrotatedExtent = transformedExtent();
Expand Down Expand Up @@ -2419,3 +2442,21 @@ void QgsComposerMap::assignFreeId()
}
mId = maxId + 1;
}

bool QgsComposerMap::imageSizeConsideringRotation( double& width, double& height ) const
{
//kept for api compatibility with QGIS 2.0 - use mMapRotation
return QgsComposerItem::imageSizeConsideringRotation( width, height, mMapRotation );
}

bool QgsComposerMap::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
{
//kept for api compatibility with QGIS 2.0 - use mMapRotation
return QgsComposerItem::cornerPointOnRotatedAndScaledRect( x, y, width, height, mMapRotation );
}

void QgsComposerMap::sizeChangedByRotation( double& width, double& height )
{
//kept for api compatibility with QGIS 2.0 - use mMapRotation
return QgsComposerItem::sizeChangedByRotation( width, height, mMapRotation );
}
37 changes: 37 additions & 0 deletions src/core/composer/qgscomposermap.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,22 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
void setCrossLength( double l ) {mCrossLength = l;}
double crossLength() {return mCrossLength;}

/**Sets rotation for the map - this does not affect the composer item shape, only the
way the map is drawn within the item
* @deprecated Use setMapRotation( double rotation ) instead
*/
void setRotation( double r );
/**Returns the rotation used for drawing the map within the composer item
* @deprecated Use mapRotation() instead
*/
double rotation() const { return mMapRotation;};

/**Sets rotation for the map - this does not affect the composer item shape, only the
way the map is drawn within the item
@note this function was added in version 2.1*/
void setMapRotation( double r );
/**Returns the rotation used for drawing the map within the composer item*/
double mapRotation() const { return mMapRotation;};

void updateItem();

Expand Down Expand Up @@ -375,9 +390,28 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
Usually, this function is called before adding the composer map to the composition*/
void assignFreeId();

/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation
* @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation )
* instead
*/
bool imageSizeConsideringRotation( double& width, double& height ) const;
/**Calculates corner point after rotation and scaling
* @deprecated Use QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation )
* instead
*/
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const;
/**Calculates width / height of the bounding box of a rotated rectangle
* @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation )
* instead
*/
void sizeChangedByRotation( double& width, double& height );

signals:
void extentChanged();

/**Is emitted on rotation change to notify north arrow pictures*/
void mapRotationChanged( double newRotation );

public slots:

/**Called if map canvas has changed*/
Expand Down Expand Up @@ -425,6 +459,9 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/**Offset in y direction for showing map cache image*/
double mYOffset;

/**Map rotation*/
double mMapRotation;

/**Flag if layers to be displayed should be read from qgis canvas (true) or from stored list in mLayerSet (false)*/
bool mKeepLayerSet;

Expand Down
69 changes: 56 additions & 13 deletions src/core/composer/qgscomposerpicture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@


QgsComposerPicture::QgsComposerPicture( QgsComposition *composition )
: QgsComposerItem( composition ), mMode( Unknown ), mRotationMap( 0 )
: QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
{
mPictureWidth = rect().width();
}

QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mRotationMap( 0 )
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
{
mPictureHeight = rect().height();
}
Expand Down Expand Up @@ -76,7 +76,7 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte

painter->save();
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
painter->rotate( mRotation );
painter->rotate( mPictureRotation );
painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );

if ( mMode == SVG )
Expand Down Expand Up @@ -214,6 +214,12 @@ void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
}

void QgsComposerPicture::setRotation( double r )
{
//kept for compatibility for QGIS2.0 api
setPictureRotation( r );
}

void QgsComposerPicture::setPictureRotation( double r )
{
//adapt rectangle size
double width = mPictureWidth;
Expand All @@ -225,7 +231,9 @@ void QgsComposerPicture::setRotation( double r )
double y = pos().y() + rect().height() / 2.0 - height / 2.0;
QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) );

QgsComposerItem::setRotation( r );
mPictureRotation = r;
update();
emit pictureRotationChanged( mPictureRotation );
}

void QgsComposerPicture::setRotationMap( int composerMapId )
Expand All @@ -237,7 +245,7 @@ void QgsComposerPicture::setRotationMap( int composerMapId )

if ( composerMapId == -1 ) //disable rotation from map
{
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
mRotationMap = 0;
}

Expand All @@ -248,12 +256,13 @@ void QgsComposerPicture::setRotationMap( int composerMapId )
}
if ( mRotationMap )
{
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
}
mRotation = map->rotation();
QObject::connect( map, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
mPictureRotation = map->mapRotation();
QObject::connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
mRotationMap = map;
setRotation( map->rotation() );
update();
emit pictureRotationChanged( mPictureRotation );
}

QString QgsComposerPicture::pictureFile() const
Expand All @@ -271,6 +280,9 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );

//rotation
composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) );
if ( !mRotationMap )
{
composerPictureElem.setAttribute( "mapId", -1 );
Expand Down Expand Up @@ -298,15 +310,28 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( composerItemList.size() > 0 )
{
_readXML( composerItemList.at( 0 ).toElement(), doc );
}
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();

if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
{
//in versions prior to 2.1 picture rotation was stored in the rotation attribute
mPictureRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
}

_readXML( composerItemElem, doc );
}

mDefaultSvgSize = QSize( 0, 0 );

QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
setPictureFile( fileName );

//picture rotation
if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 )
{
mPictureRotation = itemElem.attribute( "pictureRotation", "0" ).toDouble();
}

//rotation map
int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
if ( rotationMapId == -1 )
Expand All @@ -318,10 +343,10 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen

if ( mRotationMap )
{
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
}
mRotationMap = mComposition->getComposerMapById( rotationMapId );
QObject::connect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
QObject::connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
}

emit itemChanged();
Expand All @@ -339,3 +364,21 @@ int QgsComposerPicture::rotationMap() const
return mRotationMap->id();
}
}

bool QgsComposerPicture::imageSizeConsideringRotation( double& width, double& height ) const
{
//kept for api compatibility with QGIS 2.0 - use mPictureRotation
return QgsComposerItem::imageSizeConsideringRotation( width, height, mPictureRotation );
}

bool QgsComposerPicture::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
{
//kept for api compatibility with QGIS 2.0 - use mPictureRotation
return QgsComposerItem::cornerPointOnRotatedAndScaledRect( x, y, width, height, mPictureRotation );
}

void QgsComposerPicture::sizeChangedByRotation( double& width, double& height )
{
//kept for api compatibility with QGIS 2.0 - use mPictureRotation
return QgsComposerItem::sizeChangedByRotation( width, height, mPictureRotation );
}
42 changes: 41 additions & 1 deletion src/core/composer/qgscomposerpicture.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,54 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
*/
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );

/**Returns the rotation used for drawing the picture within the composer item
* @deprecated Use pictureRotation() instead
*/
double rotation() const { return mPictureRotation;};

/**Returns the rotation used for drawing the picture within the item
@note this function was added in version 2.1*/
double pictureRotation() const { return mPictureRotation;};

/**Sets the map object for rotation (by id). A value of -1 disables the map rotation*/
void setRotationMap( int composerMapId );
/**Returns the id of the rotation map*/
int rotationMap() const;
/**True if the rotation is taken from a map item*/
bool useRotationMap() const {return mRotationMap;}

/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation
* @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation )
* instead
*/
bool imageSizeConsideringRotation( double& width, double& height ) const;
/**Calculates corner point after rotation and scaling
* @deprecated Use QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation )
* instead
*/
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const;
/**Calculates width / height of the bounding box of a rotated rectangle
* @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation )
* instead
*/
void sizeChangedByRotation( double& width, double& height );

public slots:
/**Sets the rotation and adapts the item rect*/
/**Sets the picture rotation within the item bounds. This does not affect the item rectangle,
only the way the picture is drawn within the item.
* @deprecated Use setPictureRotation( double rotation ) instead
*/
virtual void setRotation( double r );

/**Sets the picture rotation within the item bounds. This does not affect the item rectangle,
only the way the picture is drawn within the item.
@note this function was added in version 2.1*/
virtual void setPictureRotation( double r );

signals:
/**Is emitted on picture rotation change*/
void pictureRotationChanged( double newRotation );

private:

enum Mode //SVG or raster graphic format
Expand All @@ -94,6 +131,9 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
Mode mMode;

QSize mDefaultSvgSize;

/**Image rotation*/
double mPictureRotation;
/**Map that sets the rotation (or 0 if this picture uses map independent rotation)*/
const QgsComposerMap* mRotationMap;
/**Width of the picture (in mm)*/
Expand Down
14 changes: 11 additions & 3 deletions src/core/composer/qgscomposershape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void QgsComposerShape::drawShape( QPainter* p )
p->setRenderHint( QPainter::Antialiasing );

p->translate( rect().width() / 2.0, rect().height() / 2.0 );
p->rotate( mRotation );
p->rotate( mItemRotation );
p->translate( -rect().width() / 2.0, -rect().height() / 2.0 );

switch ( mShape )
Expand Down Expand Up @@ -135,14 +135,22 @@ bool QgsComposerShape::readXML( const QDomElement& itemElem, const QDomDocument&
if ( composerItemList.size() > 0 )
{
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();

//rotation
if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
{
//check for old (pre 2.1) rotation attribute
mItemRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
}

_readXML( composerItemElem, doc );
}
emit itemChanged();
return true;
}


void QgsComposerShape::setRotation( double r )
void QgsComposerShape::setItemRotation( double r )
{
//adapt rectangle size
double width = rect().width();
Expand All @@ -154,7 +162,7 @@ void QgsComposerShape::setRotation( double r )
double y = pos().y() + rect().height() / 2.0 - height / 2.0;
QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) );

QgsComposerItem::setRotation( r );
QgsComposerItem::setItemRotation( r );
}

void QgsComposerShape::setCornerRadius( double radius )
Expand Down
2 changes: 1 addition & 1 deletion src/core/composer/qgscomposershape.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class CORE_EXPORT QgsComposerShape: public QgsComposerItem

public slots:
/**Sets item rotation and resizes item bounds such that the shape always has the same size*/
virtual void setRotation( double r );
virtual void setItemRotation( double r );

protected:
/* reimplement drawFrame, since it's not a rect, but a custom shape */
Expand Down
8 changes: 4 additions & 4 deletions src/ui/qgscomposermapwidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,16 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mRotationLabel">
<widget class="QLabel" name="mMapRotationLabel">
<property name="text">
<string>Rotation</string>
<string>Map Rotation</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="mRotationSpinBox">
<widget class="QDoubleSpinBox" name="mMapRotationSpinBox">
<property name="suffix">
<string> degrees</string>
<string> °</string>
</property>
<property name="maximum">
<double>360.000000000000000</double>
Expand Down
4 changes: 2 additions & 2 deletions src/ui/qgscomposerpicturewidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
<property name="title">
<string>Rotation</string>
<string>Image Rotation</string>
</property>
<property name="syncGroup" stdset="0">
<string notr="true">composeritem</string>
Expand All @@ -239,7 +239,7 @@
<widget class="QComboBox" name="mComposerMapComboBox"/>
</item>
<item row="0" column="0" colspan="2">
<widget class="QDoubleSpinBox" name="mRotationSpinBox">
<widget class="QDoubleSpinBox" name="mPictureRotationSpinBox">
<property name="suffix">
<string> °</string>
</property>
Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/testqgscomposermap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void TestQgsComposerMap::overviewMapCenter()
void TestQgsComposerMap::worldFileGeneration()
{
mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
mComposerMap->setRotation( 30.0 );
mComposerMap->setMapRotation( 30.0 );

mComposition->setGenerateWorldFile( true );
mComposition->setWorldFileMap( mComposerMap );
Expand Down
2 changes: 1 addition & 1 deletion tests/src/python/test_qgscomposermap.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def testZebraStyle(self):
def testWorldFileGeneration( self ):
myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125)
self.mComposerMap.setNewExtent( myRectangle )
self.mComposerMap.setRotation( 30.0 )
self.mComposerMap.setMapRotation( 30.0 )

self.mComposition.setGenerateWorldFile( True )
self.mComposition.setWorldFileMap( self.mComposerMap )
Expand Down