Skip to content

Commit 3fdf005

Browse files
author
mhugent
committedNov 2, 2009
[FEATURE]: Improve the rotation of composer pictures and added the possibility to synchronize composer map rotation and composer picture rotation (e.g. usefull for north arrows)
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@11894 c8812cc2-4d05-0410-92ff-de0c093fc19c

File tree

7 files changed

+521
-166
lines changed

7 files changed

+521
-166
lines changed
 

‎src/app/composer/qgscomposerpicturewidget.cpp

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "qgscomposerpicturewidget.h"
1919
#include "qgsapplication.h"
20+
#include "qgscomposermap.h"
2021
#include "qgscomposerpicture.h"
2122
#include "qgscomposeritemwidget.h"
2223
#include <QDoubleValidator>
@@ -34,18 +35,16 @@ QgsComposerPictureWidget::QgsComposerPictureWidget( QgsComposerPicture* picture
3435

3536
//add widget for general composer item properties
3637
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, picture );
37-
gridLayout->addWidget( itemPropertiesWidget, 6, 0, 1, 4 );
38+
gridLayout->addWidget( itemPropertiesWidget, 8, 0, 1, 4 );
3839

3940
mWidthLineEdit->setValidator( new QDoubleValidator( this ) );
4041
mHeightLineEdit->setValidator( new QDoubleValidator( this ) );
41-
4242
setGuiElementValues();
4343

4444
mPreviewListWidget->setIconSize( QSize( 30, 30 ) );
4545

4646
//add preview icons
4747
addStandardDirectoriesToPreview();
48-
4948
connect( mPicture, SIGNAL( settingsChanged() ), this, SLOT( setGuiElementValues() ) );
5049
}
5150

@@ -198,6 +197,118 @@ void QgsComposerPictureWidget::on_mRemoveDirectoryButton_clicked()
198197
}
199198
}
200199

200+
void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged( int state )
201+
{
202+
if ( !mPicture )
203+
{
204+
return;
205+
}
206+
207+
if ( state == Qt::Unchecked )
208+
{
209+
mPicture->setRotationMap( -1 );
210+
mRotationSpinBox->setEnabled( true );
211+
mComposerMapComboBox->setEnabled( false );
212+
}
213+
else
214+
{
215+
int currentItemIndex = mComposerMapComboBox->currentIndex();
216+
if ( currentItemIndex == -1 )
217+
{
218+
return;
219+
}
220+
int composerId = mComposerMapComboBox->itemData( currentItemIndex, Qt::UserRole ).toInt();
221+
mPicture->setRotationMap( composerId );
222+
mRotationSpinBox->setEnabled( false );
223+
mComposerMapComboBox->setEnabled( true );
224+
}
225+
}
226+
227+
void QgsComposerPictureWidget::showEvent( QShowEvent * event )
228+
{
229+
refreshMapComboBox();
230+
QWidget::showEvent( event );
231+
}
232+
233+
void QgsComposerPictureWidget::on_mComposerMapComboBox_activated( const QString & text )
234+
{
235+
if ( !mPicture || text.isEmpty() || !mPicture->useRotationMap() )
236+
{
237+
return;
238+
}
239+
240+
//get composition
241+
const QgsComposition* composition = mPicture->composition();
242+
if ( !composition )
243+
{
244+
return;
245+
}
246+
247+
//extract id
248+
int id;
249+
bool conversionOk;
250+
QStringList textSplit = text.split( " " );
251+
if ( textSplit.size() < 1 )
252+
{
253+
return;
254+
}
255+
256+
QString idString = textSplit.at( textSplit.size() - 1 );
257+
id = idString.toInt( &conversionOk );
258+
259+
if ( !conversionOk )
260+
{
261+
return;
262+
}
263+
264+
const QgsComposerMap* composerMap = composition->getComposerMapById( id );
265+
if ( !composerMap )
266+
{
267+
return;
268+
}
269+
mPicture->setRotationMap( id );
270+
mPicture->update();
271+
}
272+
273+
void QgsComposerPictureWidget::refreshMapComboBox()
274+
{
275+
mComposerMapComboBox->blockSignals( true );
276+
//save the current entry in case it is still present after refresh
277+
QString saveCurrentComboText = mComposerMapComboBox->currentText();
278+
279+
mComposerMapComboBox->clear();
280+
281+
if ( mPicture )
282+
{
283+
//insert available maps into mMapComboBox
284+
const QgsComposition* composition = mPicture->composition();
285+
if ( composition )
286+
{
287+
QList<const QgsComposerMap*> availableMaps = composition->composerMapItems();
288+
QList<const QgsComposerMap*>::const_iterator mapItemIt = availableMaps.constBegin();
289+
for ( ; mapItemIt != availableMaps.constEnd(); ++mapItemIt )
290+
{
291+
mComposerMapComboBox->addItem( tr( "Map %1" ).arg(( *mapItemIt )->id() ), ( *mapItemIt )->id() );
292+
}
293+
}
294+
}
295+
296+
if ( !saveCurrentComboText.isEmpty() )
297+
{
298+
if ( mComposerMapComboBox->findText( saveCurrentComboText ) == -1 )
299+
{
300+
//the former entry is no longer present. Inform the scalebar about the changed composer map
301+
on_mComposerMapComboBox_activated( mComposerMapComboBox->currentText() );
302+
}
303+
else
304+
{
305+
//the former entry is still present. Make it the current entry again
306+
mComposerMapComboBox->setCurrentIndex( mComposerMapComboBox->findText( saveCurrentComboText ) );
307+
}
308+
}
309+
mComposerMapComboBox->blockSignals( false );
310+
}
311+
201312
void QgsComposerPictureWidget::setGuiElementValues()
202313
{
203314
//set initial gui values
@@ -207,17 +318,43 @@ void QgsComposerPictureWidget::setGuiElementValues()
207318
mHeightLineEdit->blockSignals( true );
208319
mRotationSpinBox->blockSignals( true );
209320
mPictureLineEdit->blockSignals( true );
321+
mComposerMapComboBox->blockSignals( true );
322+
mRotationFromComposerMapCheckBox->blockSignals( true );
210323

211324
mPictureLineEdit->setText( mPicture->pictureFile() );
212325
QRectF pictureRect = mPicture->rect();
213326
mWidthLineEdit->setText( QString::number( pictureRect.width() ) );
214327
mHeightLineEdit->setText( QString::number( pictureRect.height() ) );
215328
mRotationSpinBox->setValue( mPicture->rotation() );
216329

330+
refreshMapComboBox();
331+
332+
if ( mPicture->useRotationMap() )
333+
{
334+
mRotationFromComposerMapCheckBox->setCheckState( Qt::Checked );
335+
mRotationSpinBox->setEnabled( false );
336+
mComposerMapComboBox->setEnabled( true );
337+
QString mapText = tr( "Map %1" ).arg( mPicture->rotationMap() );
338+
int itemId = mComposerMapComboBox->findText( mapText );
339+
if ( itemId >= 0 )
340+
{
341+
mComposerMapComboBox->setCurrentIndex( itemId );
342+
}
343+
}
344+
else
345+
{
346+
mRotationFromComposerMapCheckBox->setCheckState( Qt::Unchecked );
347+
mRotationSpinBox->setEnabled( true );
348+
mComposerMapComboBox->setEnabled( false );
349+
}
350+
351+
352+
mRotationFromComposerMapCheckBox->blockSignals( false );
217353
mWidthLineEdit->blockSignals( false );
218354
mHeightLineEdit->blockSignals( false );
219355
mRotationSpinBox->blockSignals( false );
220356
mPictureLineEdit->blockSignals( false );
357+
mComposerMapComboBox->blockSignals( false );
221358
}
222359
}
223360

@@ -302,7 +439,8 @@ void QgsComposerPictureWidget::addStandardDirectoriesToPreview()
302439
{
303440
//list all directories in $prefix/share/qgis/svg
304441
QStringList svgPaths = QgsApplication::svgPaths();
305-
for(int i=0; i<svgPaths.size(); i++) {
442+
for ( int i = 0; i < svgPaths.size(); i++ )
443+
{
306444
QDir svgDirectory( svgPaths[i] );
307445
if ( !svgDirectory.exists() || !svgDirectory.isReadable() )
308446
{
@@ -315,7 +453,7 @@ void QgsComposerPictureWidget::addStandardDirectoriesToPreview()
315453
{
316454
if ( addDirectoryToPreview( dirIt->absoluteFilePath() ) == 0 )
317455
{
318-
mSearchDirectoriesComboBox->addItem( dirIt->absoluteFilePath() );
456+
mSearchDirectoriesComboBox->addItem( dirIt->absoluteFilePath() );
319457
}
320458
}
321459
}

‎src/app/composer/qgscomposerpicturewidget.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,15 @@ class QgsComposerPictureWidget: public QWidget, private Ui::QgsComposerPictureWi
4242
void on_mPreviewListWidget_currentItemChanged( QListWidgetItem* current, QListWidgetItem* previous );
4343
void on_mAddDirectoryButton_clicked();
4444
void on_mRemoveDirectoryButton_clicked();
45+
void on_mRotationFromComposerMapCheckBox_stateChanged( int state );
46+
void on_mComposerMapComboBox_activated( const QString & text );
47+
4548
/**Sets the GUI elements to the values of mPicture*/
4649
void setGuiElementValues();
4750

51+
protected:
52+
void showEvent( QShowEvent * event );
53+
4854
private:
4955
QgsComposerPicture* mPicture;
5056
/**Add the icons of a directory to the preview. Returns 0 in case of success*/
@@ -55,6 +61,8 @@ class QgsComposerPictureWidget: public QWidget, private Ui::QgsComposerPictureWi
5561
bool testSvgFile( const QString& filename ) const;
5662
/**Tests if a file is a valid pixel format*/
5763
bool testImageFile( const QString& filename ) const;
64+
/**Updates the map combo box with the current composer map ids*/
65+
void refreshMapComboBox();
5866
};
5967

6068
#endif

‎src/core/composer/qgscomposermap.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,12 @@ void QgsComposerMap::setOffset( double xOffset, double yOffset )
505505
mYOffset = yOffset;
506506
}
507507

508+
void QgsComposerMap::setRotation( double r )
509+
{
510+
mRotation = r;
511+
emit rotationChanged( r );
512+
}
513+
508514
bool QgsComposerMap::containsWMSLayer() const
509515
{
510516
if ( !mMapRenderer )

‎src/core/composer/qgscomposermap.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class CORE_EXPORT QgsComposerMap : /*public QWidget, private Ui::QgsComposerMapB
241241

242242
/**Sets the rotation of the map content
243243
@note this function was added in version 1.4*/
244-
void setRotation( double r ) { mRotation = r; }
244+
void setRotation( double r );
245245
double rotation() const { return mRotation; }
246246

247247
/**Sets length of the cros segments (if grid style is cross)
@@ -259,6 +259,8 @@ class CORE_EXPORT QgsComposerMap : /*public QWidget, private Ui::QgsComposerMapB
259259
signals:
260260
/**Is emitted when width/height is changed as a result of user interaction*/
261261
void extentChanged();
262+
/**Is emitted on rotation change to notify north arrow pictures*/
263+
void rotationChanged( double newRotation );
262264

263265
private:
264266

‎src/core/composer/qgscomposerpicture.cpp

Lines changed: 218 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/* $Id$ */
1818

1919
#include "qgscomposerpicture.h"
20+
#include "qgscomposermap.h"
2021
#include "qgsproject.h"
2122
#include <QDomDocument>
2223
#include <QDomElement>
@@ -25,11 +26,18 @@
2526
#include <QPainter>
2627
#include <QSvgRenderer>
2728

28-
QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ): QObject( 0 ), QgsComposerItem( composition ), mRotation( 0.0 ), mMode( Unknown ), mSvgCacheUpToDate( false ), mCachedDpi( 0 )
29+
#ifndef Q_OS_MACX
30+
#include <cmath>
31+
#else
32+
#include <math.h>
33+
#endif
34+
35+
QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ): QObject( 0 ), QgsComposerItem( composition ), mRotation( 0.0 ), mMode( Unknown ), \
36+
mSvgCacheUpToDate( false ), mCachedDpi( 0 ), mRotationMap( 0 )
2937
{
3038
}
3139

32-
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mRotation( 0.0 ), mMode( Unknown ), mSvgCacheUpToDate( false )
40+
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mRotation( 0.0 ), mMode( Unknown ), mSvgCacheUpToDate( false ), mRotationMap( 0 )
3341
{
3442

3543
}
@@ -46,52 +54,61 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte
4654
return;
4755
}
4856

49-
if ( mMode == SVG )
57+
drawBackground( painter );
58+
59+
int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
60+
if ( mMode != Unknown )
5061
{
51-
int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
52-
if ( newDpi != mCachedDpi )
62+
double rectPixelWidth = rect().width() * newDpi / 25.4;
63+
double rectPixelHeight = rect().height() * newDpi / 25.4;
64+
QRectF boundRect;
65+
if ( mMode == SVG )
5366
{
54-
mSvgCacheUpToDate = false;
55-
mCachedDpi = newDpi;
56-
mImage = QImage( rect().width() * newDpi / 25.4, rect().height() * newDpi / 25.4, QImage::Format_ARGB32 );
67+
boundRect = boundedSVGRect( rectPixelWidth, rectPixelHeight );
5768
}
58-
59-
if ( !mSvgCacheUpToDate )
69+
else if ( mMode == RASTER )
6070
{
61-
updateImageFromSvg();
71+
boundRect = boundedImageRect( rectPixelWidth, rectPixelHeight );
6272
}
63-
}
6473

65-
painter->save();
66-
painter->rotate( mRotation );
67-
drawBackground( painter );
74+
double boundRectWidthMM = boundRect.width() / newDpi * 25.4;
75+
double boundRectHeightMM = boundRect.height() / newDpi * 25.4;
76+
double unrotatedBoundImageWidth = boundRect.width();
77+
double unrotatedBoundImageHeight = boundRect.height();
78+
double unrotatedBoundImageWidthMM = unrotatedBoundImageWidth / newDpi * 25.4;
79+
double unrotatedBoundImageHeightMM = unrotatedBoundImageHeight / newDpi * 25.4;
80+
double rotatedBoundImageWidth = boundRect.width();
81+
double rotatedBoundImageHeight = boundRect.height();
82+
imageSizeConsideringRotation( rotatedBoundImageWidth, rotatedBoundImageHeight );
83+
double rotatedBoundImageWidthMM = rotatedBoundImageWidth / newDpi * 25.4;
84+
double rotatedBoundImageHeightMM = rotatedBoundImageHeight / newDpi * 25.4;
6885

69-
if ( mMode != Unknown )
70-
{
71-
double widthRatio = mImage.width() / rect().width();
72-
double heightRatio = mImage.height() / rect().height();
73-
double targetWidth, targetHeight;
74-
if ( widthRatio > heightRatio )
75-
{
76-
targetWidth = rect().width();
77-
targetHeight = mImage.height() / widthRatio;
78-
}
79-
else
86+
if ( mMode == SVG )
8087
{
81-
targetHeight = rect().height();
82-
targetWidth = mImage.width() / heightRatio;
88+
if ( !mSvgCacheUpToDate )
89+
{
90+
mImage = QImage( rotatedBoundImageWidth, rotatedBoundImageHeight, QImage::Format_ARGB32 );
91+
updateImageFromSvg();
92+
}
8393
}
84-
painter->drawImage( QRectF( 0, 0, targetWidth, targetHeight ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
94+
95+
painter->save();
96+
painter->translate( boundRectWidthMM / 2.0, boundRectHeightMM / 2.0 );
97+
painter->rotate( mRotation );
98+
painter->translate( -rotatedBoundImageWidthMM / 2.0, -rotatedBoundImageHeightMM / 2.0 );
99+
painter->drawImage( QRectF( 0, 0, rotatedBoundImageWidthMM, rotatedBoundImageHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
100+
101+
painter->restore();
85102
}
86103

104+
mCachedDpi = newDpi;
105+
87106
//frame and selection boxes
88107
drawFrame( painter );
89108
if ( isSelected() )
90109
{
91110
drawSelectionBoxes( painter );
92111
}
93-
94-
painter->restore();
95112
}
96113

97114
void QgsComposerPicture::setPictureFile( const QString& path )
@@ -102,9 +119,6 @@ void QgsComposerPicture::setPictureFile( const QString& path )
102119
mMode = Unknown;
103120
}
104121

105-
//mImage = QImage(mImage.width(), mImage.height(), QImage::Format_ARGB32 );
106-
//setSceneRect
107-
108122
QFileInfo sourceFileInfo( mSourceFile );
109123
QString sourceFileSuffix = sourceFileInfo.suffix();
110124
if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
@@ -145,43 +159,124 @@ void QgsComposerPicture::setPictureFile( const QString& path )
145159
emit settingsChanged();
146160
}
147161

162+
QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
163+
{
164+
double imageToDeviceRatio;
165+
if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
166+
{
167+
imageToDeviceRatio = deviceWidth / mImage.width();
168+
double height = imageToDeviceRatio * mImage.height();
169+
return QRectF( 0, 0, deviceWidth, height );
170+
}
171+
else
172+
{
173+
imageToDeviceRatio = deviceHeight / mImage.height();
174+
double width = imageToDeviceRatio * mImage.width();
175+
return QRectF( 0, 0, width, deviceHeight );
176+
}
177+
}
178+
179+
QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
180+
{
181+
double imageToSvgRatio;
182+
if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
183+
{
184+
imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
185+
double height = mDefaultSvgSize.height() * imageToSvgRatio;
186+
return QRectF( 0, 0, deviceWidth, height );
187+
}
188+
else
189+
{
190+
imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
191+
double width = mDefaultSvgSize.width() * imageToSvgRatio;
192+
return QRectF( 0, 0, width, deviceHeight );
193+
}
194+
}
195+
148196
void QgsComposerPicture::updateImageFromSvg()
149197
{
150198
mImage.fill( 0 );
151199
QPainter p( &mImage );
152200
p.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing, true );
153201
QSvgRenderer theRenderer( mSourceFile.fileName() );
154-
if ( theRenderer.isValid() )
155-
{
156-
theRenderer.render( &p );
157-
}
202+
theRenderer.render( &p );
158203
mSvgCacheUpToDate = true;
159204
}
160205

161-
void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
206+
bool QgsComposerPicture::imageSizeConsideringRotation( double& width, double& height ) const
162207
{
163-
mSvgCacheUpToDate = false;
164-
if ( mMode == SVG )
208+
double x1 = 0;
209+
double y1 = 0;
210+
double x2 = width;
211+
double y2 = 0;
212+
double x3 = width;
213+
double y3 = height;
214+
double x4 = 0;
215+
double y4 = height;
216+
217+
if ( !cornerPointOnRotatedAndScaledRect( x1, y1, width, height ) )
165218
{
166-
//keep aspect ratio
167-
double widthRatio = rectangle.width() / mDefaultSvgSize.width();
168-
double heightRatio = rectangle.height() / mDefaultSvgSize.height();
219+
return false;
220+
}
221+
if ( !cornerPointOnRotatedAndScaledRect( x2, y2, width, height ) )
222+
{
223+
return false;
224+
}
225+
if ( !cornerPointOnRotatedAndScaledRect( x3, y3, width, height ) )
226+
{
227+
return false;
228+
}
229+
/*
230+
if(!cornerPointOnRotatedAndScaledRect(x4, y4, width, height))
231+
{
232+
return false;
233+
}*/
169234

170-
double newImageWidth;
171-
double newImageHeight;
235+
width = sqrt(( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) );
236+
height = sqrt(( x3 - x2 ) * ( x3 - x2 ) + ( y3 - y2 ) * ( y3 - y2 ) );
237+
return true;
238+
}
172239

173-
if ( widthRatio > heightRatio )
174-
{
175-
newImageWidth = rectangle.width() * mCachedDpi / 25.4;
176-
newImageHeight = mDefaultSvgSize.height() * widthRatio * mCachedDpi / 25.4;
177-
}
178-
else
240+
bool QgsComposerPicture::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
241+
{
242+
//first rotate point clockwise
243+
double rotToRad = mRotation * M_PI / 180.0;
244+
QPointF midpoint( width / 2.0, height / 2.0 );
245+
double xVector = x - midpoint.x();
246+
double yVector = y - midpoint.y();
247+
//double xRotated = cos(rotToRad) * xVector + sin(rotToRad) * yVector;
248+
//double yRotated = -sin(rotToRad) * xVector + cos(rotToRad) * yVector;
249+
double xRotated = cos( rotToRad ) * xVector - sin( rotToRad ) * yVector;
250+
double yRotated = sin( rotToRad ) * xVector + cos( rotToRad ) * yVector;
251+
252+
//create line from midpoint to rotated point
253+
QLineF line( midpoint.x(), midpoint.y(), midpoint.x() + xRotated, midpoint.y() + yRotated );
254+
255+
//intersect with all four borders and return result
256+
QList<QLineF> borders;
257+
borders << QLineF( 0, 0, width, 0 );
258+
borders << QLineF( width, 0, width, height );
259+
borders << QLineF( width, height, 0, height );
260+
borders << QLineF( 0, height, 0, 0 );
261+
262+
QList<QLineF>::const_iterator it = borders.constBegin();
263+
QPointF intersectionPoint;
264+
265+
for ( ; it != borders.constEnd(); ++it )
266+
{
267+
if ( line.intersect( *it, &intersectionPoint ) == QLineF::BoundedIntersection )
179268
{
180-
newImageHeight = rectangle.height() * mCachedDpi / 25.4;
181-
newImageWidth = mDefaultSvgSize.width() * heightRatio * mCachedDpi / 25.4;
269+
x = intersectionPoint.x();
270+
y = intersectionPoint.y();
271+
return true;
182272
}
183-
mImage = QImage( newImageWidth, newImageHeight, QImage::Format_ARGB32 );
184273
}
274+
return false;
275+
}
276+
277+
void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
278+
{
279+
mSvgCacheUpToDate = false;
185280
QgsComposerItem::setSceneRect( rectangle );
186281
emit settingsChanged();
187282
}
@@ -196,6 +291,35 @@ void QgsComposerPicture::setRotation( double rotation )
196291
{
197292
mRotation = rotation;
198293
}
294+
emit settingsChanged();
295+
update();
296+
}
297+
298+
void QgsComposerPicture::setRotationMap( int composerMapId )
299+
{
300+
if ( !mComposition )
301+
{
302+
return;
303+
}
304+
305+
if ( composerMapId == -1 ) //disable rotation from map
306+
{
307+
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
308+
mRotationMap = 0;
309+
}
310+
311+
const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
312+
if ( !map )
313+
{
314+
return;
315+
}
316+
if ( mRotationMap )
317+
{
318+
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
319+
}
320+
mRotation = map->rotation();
321+
QObject::connect( map, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
322+
mRotationMap = map;
199323
}
200324

201325
QString QgsComposerPicture::pictureFile() const
@@ -212,6 +336,15 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
212336
QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
213337
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
214338
composerPictureElem.setAttribute( "rotation", QString::number( mRotation ) );
339+
if ( !mRotationMap )
340+
{
341+
composerPictureElem.setAttribute( "mapId", -1 );
342+
}
343+
else
344+
{
345+
composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
346+
}
347+
215348
_writeXML( composerPictureElem, doc );
216349
elem.appendChild( composerPictureElem );
217350
return true;
@@ -230,6 +363,7 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
230363
_readXML( composerItemList.at( 0 ).toElement(), doc );
231364
}
232365

366+
233367
mSvgCacheUpToDate = false;
234368
mDefaultSvgSize = QSize( 0, 0 );
235369
mCachedDpi = 0;
@@ -239,5 +373,34 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
239373

240374
mRotation = itemElem.attribute( "rotation" ).toDouble();
241375

376+
//rotation map
377+
int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
378+
if ( rotationMapId == -1 )
379+
{
380+
mRotationMap = 0;
381+
}
382+
else if ( mComposition )
383+
{
384+
385+
if ( mRotationMap )
386+
{
387+
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
388+
}
389+
mRotationMap = mComposition->getComposerMapById( rotationMapId );
390+
QObject::connect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
391+
}
392+
242393
return true;
243394
}
395+
396+
int QgsComposerPicture::rotationMap() const
397+
{
398+
if ( !mRotationMap )
399+
{
400+
return -1;
401+
}
402+
else
403+
{
404+
return mRotationMap->id();
405+
}
406+
}

‎src/core/composer/qgscomposerpicture.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ class CORE_EXPORT QgsComposerPicture: public QObject, public QgsComposerItem
4343
corresponds to 1 scene size unit*/
4444
void setSceneRect( const QRectF& rectangle );
4545

46-
void setRotation( double rotation );
47-
4846
double rotation() const {return mRotation;}
4947

5048
/** stores state in Dom node
@@ -58,6 +56,17 @@ class CORE_EXPORT QgsComposerPicture: public QObject, public QgsComposerItem
5856
*/
5957
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );
6058

59+
/**Sets the map object for rotation (by id). A value of -1 disables the map rotation*/
60+
void setRotationMap( int composerMapId );
61+
/**Returns the id of the rotation map*/
62+
int rotationMap() const;
63+
/**True if the rotation is taken from a map item*/
64+
bool useRotationMap() const {return mRotationMap;}
65+
66+
public slots:
67+
68+
void setRotation( double rotation );
69+
6170
private:
6271

6372
enum Mode //SVG or raster graphic format
@@ -69,8 +78,19 @@ class CORE_EXPORT QgsComposerPicture: public QObject, public QgsComposerItem
6978

7079
//default constructor is forbidden
7180
QgsComposerPicture();
72-
/**Updates content of current image using svg generator*/
81+
/**Calculates bounding rect for svg file (mSourcefile) such that aspect ratio is correct*/
82+
QRectF boundedSVGRect( double deviceWidth, double deviceHeight );
83+
/**Calculates bounding rect for image such that aspect ratio is correct*/
84+
QRectF boundedImageRect( double deviceWidth, double deviceHeight );
85+
86+
/**Updates content of mImage using svg generator
87+
@param out: boundWidth width of mImage that is used by the svg renderer. May different from mImage.width() to preserve aspect ratio
88+
@param out: boundHeight height of mImage that is used by the svg renderer*/
7389
void updateImageFromSvg();
90+
/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation*/
91+
bool imageSizeConsideringRotation( double& width, double& height ) const;
92+
/**Calculates corner point after rotation and scaling*/
93+
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const;
7494

7595
QImage mImage;
7696
double mRotation;
@@ -80,6 +100,9 @@ class CORE_EXPORT QgsComposerPicture: public QObject, public QgsComposerItem
80100
bool mSvgCacheUpToDate;
81101
int mCachedDpi; //store dpis for which the svg cache is valid
82102
QSize mDefaultSvgSize;
103+
/**Map that sets the rotation (or 0 if this picture uses map independent rotation)*/
104+
const QgsComposerMap* mRotationMap;
105+
83106

84107
signals:
85108
/**Tell the configuration widget that the settings need to be updated*/

‎src/ui/qgscomposerpicturewidgetbase.ui

Lines changed: 117 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,238 @@
1-
<ui version="4.0" >
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
23
<class>QgsComposerPictureWidgetBase</class>
3-
<widget class="QWidget" name="QgsComposerPictureWidgetBase" >
4-
<property name="geometry" >
4+
<widget class="QWidget" name="QgsComposerPictureWidgetBase">
5+
<property name="geometry">
56
<rect>
67
<x>0</x>
78
<y>0</y>
8-
<width>342</width>
9+
<width>299</width>
910
<height>613</height>
1011
</rect>
1112
</property>
12-
<property name="sizePolicy" >
13-
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
13+
<property name="sizePolicy">
14+
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1415
<horstretch>0</horstretch>
1516
<verstretch>0</verstretch>
1617
</sizepolicy>
1718
</property>
18-
<property name="windowTitle" >
19+
<property name="windowTitle">
1920
<string>Picture Options</string>
2021
</property>
21-
<layout class="QGridLayout" >
22-
<item row="0" column="0" colspan="4" >
23-
<widget class="QGroupBox" name="mSearchDirectoriesGroupBox" >
24-
<property name="sizePolicy" >
25-
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
22+
<layout class="QGridLayout" name="gridLayout">
23+
<item row="0" column="0" colspan="2">
24+
<widget class="QGroupBox" name="mSearchDirectoriesGroupBox">
25+
<property name="sizePolicy">
26+
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
2627
<horstretch>0</horstretch>
2728
<verstretch>0</verstretch>
2829
</sizepolicy>
2930
</property>
30-
<property name="title" >
31+
<property name="title">
3132
<string>Search directories</string>
3233
</property>
33-
<layout class="QGridLayout" >
34-
<item row="0" column="0" colspan="3" >
35-
<widget class="QComboBox" name="mSearchDirectoriesComboBox" >
36-
<property name="sizePolicy" >
37-
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
34+
<layout class="QGridLayout">
35+
<item row="0" column="0" colspan="3">
36+
<widget class="QComboBox" name="mSearchDirectoriesComboBox">
37+
<property name="sizePolicy">
38+
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
3839
<horstretch>0</horstretch>
3940
<verstretch>0</verstretch>
4041
</sizepolicy>
4142
</property>
4243
</widget>
4344
</item>
44-
<item row="1" column="0" >
45+
<item row="1" column="0">
4546
<spacer>
46-
<property name="orientation" >
47+
<property name="orientation">
4748
<enum>Qt::Horizontal</enum>
4849
</property>
49-
<property name="sizeHint" >
50+
<property name="sizeHint" stdset="0">
5051
<size>
5152
<width>101</width>
5253
<height>20</height>
5354
</size>
5455
</property>
5556
</spacer>
5657
</item>
57-
<item row="1" column="1" >
58-
<widget class="QPushButton" name="mAddDirectoryButton" >
59-
<property name="text" >
58+
<item row="1" column="1">
59+
<widget class="QPushButton" name="mAddDirectoryButton">
60+
<property name="text">
6061
<string>Add...</string>
6162
</property>
6263
</widget>
6364
</item>
64-
<item row="1" column="2" >
65-
<widget class="QPushButton" name="mRemoveDirectoryButton" >
66-
<property name="text" >
65+
<item row="1" column="2">
66+
<widget class="QPushButton" name="mRemoveDirectoryButton">
67+
<property name="text">
6768
<string>Remove</string>
6869
</property>
6970
</widget>
7071
</item>
7172
</layout>
7273
</widget>
7374
</item>
74-
<item row="1" column="0" colspan="4" >
75-
<widget class="QGroupBox" name="mPreviewGroupBox" >
76-
<property name="sizePolicy" >
77-
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
75+
<item row="1" column="0" colspan="2">
76+
<widget class="QGroupBox" name="mPreviewGroupBox">
77+
<property name="sizePolicy">
78+
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
7879
<horstretch>0</horstretch>
7980
<verstretch>0</verstretch>
8081
</sizepolicy>
8182
</property>
82-
<property name="title" >
83+
<property name="title">
8384
<string>Preview</string>
8485
</property>
85-
<layout class="QGridLayout" >
86-
<item row="0" column="0" >
87-
<widget class="QListWidget" name="mPreviewListWidget" >
88-
<property name="showDropIndicator" stdset="0" >
86+
<layout class="QGridLayout">
87+
<item row="0" column="0">
88+
<widget class="QListWidget" name="mPreviewListWidget">
89+
<property name="showDropIndicator" stdset="0">
8990
<bool>false</bool>
9091
</property>
91-
<property name="dragDropMode" >
92+
<property name="dragDropMode">
9293
<enum>QAbstractItemView::DragDrop</enum>
9394
</property>
94-
<property name="movement" >
95+
<property name="movement">
9596
<enum>QListView::Free</enum>
9697
</property>
97-
<property name="flow" >
98+
<property name="flow">
9899
<enum>QListView::LeftToRight</enum>
99100
</property>
100-
<property name="isWrapping" stdset="0" >
101+
<property name="isWrapping" stdset="0">
101102
<bool>true</bool>
102103
</property>
103-
<property name="gridSize" >
104+
<property name="gridSize">
104105
<size>
105106
<width>30</width>
106107
<height>30</height>
107108
</size>
108109
</property>
109-
<property name="viewMode" >
110+
<property name="viewMode">
110111
<enum>QListView::IconMode</enum>
111112
</property>
112-
<property name="wordWrap" >
113+
<property name="wordWrap">
113114
<bool>true</bool>
114115
</property>
115116
</widget>
116117
</item>
117118
</layout>
118119
</widget>
119120
</item>
120-
<item row="2" column="0" >
121-
<widget class="QLabel" name="label" >
122-
<property name="text" >
123-
<string>Load</string>
124-
</property>
125-
<property name="buddy" >
126-
<cstring>mPictureLineEdit</cstring>
127-
</property>
128-
</widget>
129-
</item>
130-
<item row="2" column="1" colspan="2" >
131-
<widget class="QLineEdit" name="mPictureLineEdit" />
132-
</item>
133-
<item row="2" column="3" >
134-
<widget class="QPushButton" name="mPictureBrowseButton" >
135-
<property name="sizePolicy" >
136-
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
137-
<horstretch>0</horstretch>
138-
<verstretch>0</verstretch>
139-
</sizepolicy>
140-
</property>
141-
<property name="maximumSize" >
142-
<size>
143-
<width>150</width>
144-
<height>32767</height>
145-
</size>
146-
</property>
147-
<property name="text" >
148-
<string>...</string>
149-
</property>
150-
</widget>
121+
<item row="2" column="0" colspan="2">
122+
<layout class="QHBoxLayout" name="horizontalLayout">
123+
<item>
124+
<widget class="QLabel" name="label">
125+
<property name="text">
126+
<string>Load</string>
127+
</property>
128+
<property name="buddy">
129+
<cstring>mPictureLineEdit</cstring>
130+
</property>
131+
</widget>
132+
</item>
133+
<item>
134+
<widget class="QLineEdit" name="mPictureLineEdit"/>
135+
</item>
136+
<item>
137+
<widget class="QPushButton" name="mPictureBrowseButton">
138+
<property name="sizePolicy">
139+
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
140+
<horstretch>0</horstretch>
141+
<verstretch>0</verstretch>
142+
</sizepolicy>
143+
</property>
144+
<property name="maximumSize">
145+
<size>
146+
<width>150</width>
147+
<height>32767</height>
148+
</size>
149+
</property>
150+
<property name="text">
151+
<string>...</string>
152+
</property>
153+
</widget>
154+
</item>
155+
</layout>
151156
</item>
152-
<item row="3" column="0" >
153-
<widget class="QLabel" name="textLabel3" >
154-
<property name="sizePolicy" >
155-
<sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
157+
<item row="3" column="0">
158+
<widget class="QLabel" name="textLabel3">
159+
<property name="sizePolicy">
160+
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
156161
<horstretch>0</horstretch>
157162
<verstretch>0</verstretch>
158163
</sizepolicy>
159164
</property>
160-
<property name="text" >
165+
<property name="text">
161166
<string>Width</string>
162167
</property>
163-
<property name="wordWrap" >
168+
<property name="wordWrap">
164169
<bool>true</bool>
165170
</property>
166-
<property name="buddy" >
171+
<property name="buddy">
167172
<cstring>mWidthLineEdit</cstring>
168173
</property>
169174
</widget>
170175
</item>
171-
<item row="3" column="1" colspan="3" >
172-
<widget class="QLineEdit" name="mWidthLineEdit" />
176+
<item row="3" column="1">
177+
<widget class="QLineEdit" name="mWidthLineEdit"/>
173178
</item>
174-
<item row="4" column="0" >
175-
<widget class="QLabel" name="textLabel4" >
176-
<property name="sizePolicy" >
177-
<sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
179+
<item row="4" column="0">
180+
<widget class="QLabel" name="textLabel4">
181+
<property name="sizePolicy">
182+
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
178183
<horstretch>0</horstretch>
179184
<verstretch>0</verstretch>
180185
</sizepolicy>
181186
</property>
182-
<property name="text" >
187+
<property name="text">
183188
<string>Height</string>
184189
</property>
185-
<property name="wordWrap" >
190+
<property name="wordWrap">
186191
<bool>true</bool>
187192
</property>
188-
<property name="buddy" >
193+
<property name="buddy">
189194
<cstring>mHeightLineEdit</cstring>
190195
</property>
191196
</widget>
192197
</item>
193-
<item row="4" column="1" colspan="3" >
194-
<widget class="QLineEdit" name="mHeightLineEdit" />
198+
<item row="4" column="1">
199+
<widget class="QLineEdit" name="mHeightLineEdit"/>
195200
</item>
196-
<item row="5" column="0" colspan="2" >
197-
<widget class="QLabel" name="mRotationLabel" >
198-
<property name="sizePolicy" >
199-
<sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
201+
<item row="5" column="0">
202+
<widget class="QLabel" name="mRotationLabel">
203+
<property name="sizePolicy">
204+
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
200205
<horstretch>0</horstretch>
201206
<verstretch>0</verstretch>
202207
</sizepolicy>
203208
</property>
204-
<property name="text" >
209+
<property name="text">
205210
<string>Rotation</string>
206211
</property>
207-
<property name="wordWrap" >
212+
<property name="wordWrap">
208213
<bool>true</bool>
209214
</property>
210-
<property name="buddy" >
215+
<property name="buddy">
211216
<cstring>mRotationSpinBox</cstring>
212217
</property>
213218
</widget>
214219
</item>
215-
<item row="5" column="2" colspan="2" >
216-
<widget class="QDoubleSpinBox" name="mRotationSpinBox" />
220+
<item row="5" column="1">
221+
<widget class="QDoubleSpinBox" name="mRotationSpinBox"/>
222+
</item>
223+
<item row="6" column="0" colspan="2">
224+
<widget class="QCheckBox" name="mRotationFromComposerMapCheckBox">
225+
<property name="text">
226+
<string>Take rotation from composer map</string>
227+
</property>
228+
</widget>
229+
</item>
230+
<item row="7" column="0" colspan="2">
231+
<widget class="QComboBox" name="mComposerMapComboBox"/>
217232
</item>
218233
</layout>
219234
</widget>
220-
<layoutdefault spacing="6" margin="11" />
235+
<layoutdefault spacing="6" margin="11"/>
221236
<tabstops>
222237
<tabstop>mSearchDirectoriesComboBox</tabstop>
223238
<tabstop>mAddDirectoryButton</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.