Skip to content

Commit 01b3d96

Browse files
committed
[composer] Fix order of vertices returned by mapPolygon when map rotation is set, fix drawing overview frame when either map is rotated (fix #10644)
1 parent 39e5c85 commit 01b3d96

File tree

6 files changed

+124
-24
lines changed

6 files changed

+124
-24
lines changed

python/core/composer/qgscomposermap.sip

+13-2
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ class QgsComposerMap : QgsComposerItem
141141
void toggleAtlasPreview();
142142

143143
/**Returns a pointer to the current map extent, which is either the original user specified
144-
extent or the temporary atlas-driven feature extent depending on the current atlas state of the composition.
145-
Both a const and non-const version are included.*/
144+
* extent or the temporary atlas-driven feature extent depending on the current atlas state
145+
* of the composition. Both a const and non-const version are included.
146+
* @returns pointer to current map extent
147+
* @see visibleExtentPolygon
148+
*/
146149
const QgsRectangle* currentMapExtent() const;
147150

148151
PreviewMode previewMode() const;
@@ -478,6 +481,14 @@ class QgsComposerMap : QgsComposerItem
478481
*/
479482
int numberExportLayers() const;
480483

484+
/**Returns a polygon representing the current visible map extent, considering map extents and rotation.
485+
* If the map rotation is 0, the result is the same as currentMapExtent
486+
* @returns polygon with the four corner points representing the visible map extent. The points are
487+
* clockwise, starting at the top-left point
488+
* @see currentMapExtent
489+
*/
490+
QPolygonF visibleExtentPolygon() const;
491+
481492
signals:
482493
void extentChanged();
483494

src/core/composer/qgscomposermap.cpp

+24-16
Original file line numberDiff line numberDiff line change
@@ -2075,8 +2075,7 @@ QPolygonF QgsComposerMap::transformedMapPolygon() const
20752075
//qWarning("transformed:");
20762076
//qWarning(QString::number(dx).toLocal8Bit().data());
20772077
//qWarning(QString::number(dy).toLocal8Bit().data());
2078-
QPolygonF poly;
2079-
mapPolygon( poly );
2078+
QPolygonF poly = visibleExtentPolygon();
20802079
poly.translate( -dx, -dy );
20812080
return poly;
20822081
}
@@ -2146,30 +2145,32 @@ void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) c
21462145
dx = rotationPoint.x() - extent.xMinimum();
21472146
dy = rotationPoint.y() - extent.yMaximum();
21482147
rotate( mMapRotation, dx, dy );
2149-
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2148+
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
21502149

21512150
//top right point
21522151
dx = rotationPoint.x() - extent.xMaximum();
21532152
dy = rotationPoint.y() - extent.yMaximum();
21542153
rotate( mMapRotation, dx, dy );
2155-
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2154+
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
21562155

21572156
//bottom right point
21582157
dx = rotationPoint.x() - extent.xMaximum();
21592158
dy = rotationPoint.y() - extent.yMinimum();
21602159
rotate( mMapRotation, dx, dy );
2161-
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2160+
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
21622161

21632162
//bottom left point
21642163
dx = rotationPoint.x() - extent.xMinimum();
21652164
dy = rotationPoint.y() - extent.yMinimum();
21662165
rotate( mMapRotation, dx, dy );
2167-
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2166+
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
21682167
}
21692168

2170-
void QgsComposerMap::mapPolygon( QPolygonF& poly ) const
2169+
QPolygonF QgsComposerMap::visibleExtentPolygon() const
21712170
{
2172-
return mapPolygon( *currentMapExtent(), poly );
2171+
QPolygonF poly;
2172+
mapPolygon( *currentMapExtent(), poly );
2173+
return poly;
21732174
}
21742175

21752176
void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const
@@ -2569,9 +2570,13 @@ void QgsComposerMap::drawOverviewMapExtent( QPainter* p )
25692570
return;
25702571
}
25712572

2572-
QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
2573-
QgsRectangle thisExtent = *currentMapExtent();
2574-
QgsRectangle intersectRect = thisExtent.intersect( &otherExtent );
2573+
//get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
2574+
QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
2575+
2576+
//get current map's extent as a QPolygonF
2577+
QPolygonF thisExtent = visibleExtentPolygon();
2578+
//intersect the two
2579+
QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
25752580

25762581
//setup painter scaling to dots so that raster symbology is drawn to scale
25772582
double dotsPerMM = p->device()->logicalDpiX() / 25.4;
@@ -2596,12 +2601,15 @@ void QgsComposerMap::drawOverviewMapExtent( QPainter* p )
25962601

25972602
//construct a polygon corresponding to the intersecting map extent
25982603
//need to scale line to dots, rather then mm, since the painter has been scaled to dots
2604+
QTransform mapTransform;
2605+
QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * rect().width(), dotsPerMM * rect().height() ) );
2606+
2607+
//workaround QT Bug #21329
2608+
thisRectPoly.pop_back();
2609+
//create transform from map coordinates to painter coordinates
2610+
QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
25992611
QPolygonF intersectPolygon;
2600-
double x = dotsPerMM * ( intersectRect.xMinimum() - thisExtent.xMinimum() ) / thisExtent.width() * rect().width();
2601-
double y = dotsPerMM * ( thisExtent.yMaximum() - intersectRect.yMaximum() ) / thisExtent.height() * rect().height();
2602-
double width = dotsPerMM * intersectRect.width() / thisExtent.width() * rect().width();
2603-
double height = dotsPerMM * intersectRect.height() / thisExtent.height() * rect().height();
2604-
intersectPolygon << QPointF( x, y ) << QPointF( x + width, y ) << QPointF( x + width, y + height ) << QPointF( x, y + height ) << QPointF( x, y );
2612+
intersectPolygon = mapTransform.map( intersectExtent );
26052613

26062614
QList<QPolygonF> rings; //empty list
26072615
if ( !mOverviewInverted )

src/core/composer/qgscomposermap.h

+14-6
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,11 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
175175
void toggleAtlasPreview();
176176

177177
/**Returns a pointer to the current map extent, which is either the original user specified
178-
extent or the temporary atlas-driven feature extent depending on the current atlas state of the composition.
179-
Both a const and non-const version are included.*/
178+
* extent or the temporary atlas-driven feature extent depending on the current atlas state
179+
* of the composition. Both a const and non-const version are included.
180+
* @returns pointer to current map extent
181+
* @see visibleExtentPolygon
182+
*/
180183
QgsRectangle* currentMapExtent();
181184
const QgsRectangle* currentMapExtent() const;
182185

@@ -513,6 +516,14 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
513516
*/
514517
int numberExportLayers() const;
515518

519+
/**Returns a polygon representing the current visible map extent, considering map extents and rotation.
520+
* If the map rotation is 0, the result is the same as currentMapExtent
521+
* @returns polygon with the four corner points representing the visible map extent. The points are
522+
* clockwise, starting at the top-left point
523+
* @see currentMapExtent
524+
*/
525+
QPolygonF visibleExtentPolygon() const;
526+
516527
signals:
517528
void extentChanged();
518529

@@ -703,10 +714,7 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
703714
/**Returns extent that considers rotation and shift with mOffsetX / mOffsetY*/
704715
QPolygonF transformedMapPolygon() const;
705716
double maxExtension() const;
706-
/**Returns the polygon of the map extent. If rotation == 0, the result is the same as mExtent
707-
@param poly out: the result polygon with the four corner points. The points are clockwise, starting at the top-left point
708-
@return true in case of success*/
709-
void mapPolygon( QPolygonF& poly ) const;
717+
710718
/** mapPolygon variant using a given extent */
711719
void mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const;
712720

tests/src/core/testqgscomposermap.cpp

+73
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,15 @@ class TestQgsComposerMap: public QObject
3939
void grid(); //test if grid and grid annotation works
4040
void crossGrid(); //test if grid "cross" mode works
4141
void overviewMap(); //test if overview map frame works
42+
void overviewMapRotated(); //test if overview map frame works with rotated overview
43+
void overviewMapRotated2(); //test if overview map frame works with rotated map
4244
void overviewMapBlending(); //test if blend modes with overview map frame works
4345
void overviewMapInvert(); //test if invert of overview map frame works
4446
void uniqueId(); //test if map id is adapted when doing copy paste
4547
void zebraStyle(); //test zebra map border style
4648
void overviewMapCenter(); //test if centering of overview map frame works
4749
void worldFileGeneration(); // test world file generation
50+
void mapPolygonVertices(); // test mapPolygon function with no map rotation
4851

4952
private:
5053
QgsComposition* mComposition;
@@ -176,6 +179,39 @@ void TestQgsComposerMap::overviewMap()
176179
QVERIFY( testResult );
177180
}
178181

182+
void TestQgsComposerMap::overviewMapRotated()
183+
{
184+
QgsComposerMap* overviewMap = new QgsComposerMap( mComposition, 20, 130, 70, 70 );
185+
overviewMap->setFrameEnabled( true );
186+
mComposition->addComposerMap( overviewMap );
187+
mComposerMap->setNewExtent( QgsRectangle( 785462.375, 3341423.125, 789262.375, 3343323.125 ) ); //zoom in
188+
mComposerMap->setMapRotation( 30 );
189+
overviewMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3350923.125 ) );
190+
overviewMap->setOverviewFrameMap( mComposerMap->id() );
191+
QgsCompositionChecker checker( "composermap_overview_rotated", mComposition );
192+
193+
bool testResult = checker.testComposition( mReport, 0, 100 );
194+
mComposition->removeComposerItem( overviewMap );
195+
mComposerMap->setMapRotation( 0 );
196+
QVERIFY( testResult );
197+
}
198+
199+
void TestQgsComposerMap::overviewMapRotated2()
200+
{
201+
QgsComposerMap* overviewMap = new QgsComposerMap( mComposition, 20, 130, 70, 70 );
202+
overviewMap->setFrameEnabled( true );
203+
mComposition->addComposerMap( overviewMap );
204+
mComposerMap->setNewExtent( QgsRectangle( 785462.375, 3341423.125, 789262.375, 3343323.125 ) ); //zoom in
205+
overviewMap->setMapRotation( 30 );
206+
overviewMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3350923.125 ) );
207+
overviewMap->setOverviewFrameMap( mComposerMap->id() );
208+
QgsCompositionChecker checker( "composermap_overview_rotated2", mComposition );
209+
210+
bool testResult = checker.testComposition( mReport, 0, 100 );
211+
mComposition->removeComposerItem( overviewMap );
212+
QVERIFY( testResult );
213+
}
214+
179215
void TestQgsComposerMap::overviewMapBlending()
180216
{
181217
QgsComposerMap* overviewMapBlend = new QgsComposerMap( mComposition, 20, 130, 70, 70 );
@@ -292,6 +328,43 @@ void TestQgsComposerMap::worldFileGeneration()
292328
QVERIFY( fabs( d - 2.4136 ) < 0.001 );
293329
QVERIFY( fabs( e + 4.17997 ) < 0.001 );
294330
QVERIFY( fabs( f - 3.34241e+06 ) < 1e+03 );
331+
332+
mComposition->setGenerateWorldFile( false );
333+
mComposerMap->setMapRotation( 0.0 );
334+
335+
}
336+
337+
void TestQgsComposerMap::mapPolygonVertices()
338+
{
339+
mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
340+
QPolygonF visibleExtent = mComposerMap->visibleExtentPolygon();
341+
342+
//vertices should be returned in clockwise order starting at the top-left point
343+
QVERIFY( fabs( visibleExtent[0].x() - 781662.375 ) < 0.001 );
344+
QVERIFY( fabs( visibleExtent[0].y() - 3345223.125 ) < 0.001 );
345+
QVERIFY( fabs( visibleExtent[1].x() - 793062.375 ) < 0.001 );
346+
QVERIFY( fabs( visibleExtent[1].y() - 3345223.125 ) < 0.001 );
347+
QVERIFY( fabs( visibleExtent[2].x() - 793062.375 ) < 0.001 );
348+
QVERIFY( fabs( visibleExtent[2].y() - 3339523.125 ) < 0.001 );
349+
QVERIFY( fabs( visibleExtent[3].x() - 781662.375 ) < 0.001 );
350+
QVERIFY( fabs( visibleExtent[3].y() - 3339523.125 ) < 0.001 );
351+
352+
//now test with rotated map
353+
mComposerMap->setMapRotation( 10 );
354+
visibleExtent = mComposerMap->visibleExtentPolygon();
355+
356+
//vertices should be returned in clockwise order starting at the top-left point
357+
QVERIFY( fabs( visibleExtent[0].x() - 781254.0735015 ) < 0.001 );
358+
QVERIFY( fabs( visibleExtent[0].y() - 3344190.0324834 ) < 0.001 );
359+
QVERIFY( fabs( visibleExtent[1].x() - 792480.881886 ) < 0.001 );
360+
QVERIFY( fabs( visibleExtent[1].y() - 3346169.62171 ) < 0.001 );
361+
QVERIFY( fabs( visibleExtent[2].x() - 793470.676499 ) < 0.001 );
362+
QVERIFY( fabs( visibleExtent[2].y() - 3340556.21752 ) < 0.001 );
363+
QVERIFY( fabs( visibleExtent[3].x() - 782243.868114 ) < 0.001 );
364+
QVERIFY( fabs( visibleExtent[3].y() - 3338576.62829 ) < 0.001 );
365+
366+
mComposerMap->setMapRotation( 0 );
367+
295368
}
296369

297370
QTEST_MAIN( TestQgsComposerMap )

0 commit comments

Comments
 (0)