Skip to content
Permalink
Browse files
[composer] Fix order of vertices returned by mapPolygon when map rota…
…tion is set, fix drawing overview frame when either map is rotated (fix #10644)
  • Loading branch information
nyalldawson committed Jun 23, 2014
1 parent 39e5c85 commit 01b3d9662c53d78a4c746cf408b45aa21e14cd5b
@@ -141,8 +141,11 @@ class QgsComposerMap : QgsComposerItem
void toggleAtlasPreview();

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

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

/**Returns a polygon representing the current visible map extent, considering map extents and rotation.
* If the map rotation is 0, the result is the same as currentMapExtent
* @returns polygon with the four corner points representing the visible map extent. The points are
* clockwise, starting at the top-left point
* @see currentMapExtent
*/
QPolygonF visibleExtentPolygon() const;

signals:
void extentChanged();

@@ -2075,8 +2075,7 @@ QPolygonF QgsComposerMap::transformedMapPolygon() const
//qWarning("transformed:");
//qWarning(QString::number(dx).toLocal8Bit().data());
//qWarning(QString::number(dy).toLocal8Bit().data());
QPolygonF poly;
mapPolygon( poly );
QPolygonF poly = visibleExtentPolygon();
poly.translate( -dx, -dy );
return poly;
}
@@ -2146,30 +2145,32 @@ void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) c
dx = rotationPoint.x() - extent.xMinimum();
dy = rotationPoint.y() - extent.yMaximum();
rotate( mMapRotation, dx, dy );
poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );

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

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

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

void QgsComposerMap::mapPolygon( QPolygonF& poly ) const
QPolygonF QgsComposerMap::visibleExtentPolygon() const
{
return mapPolygon( *currentMapExtent(), poly );
QPolygonF poly;
mapPolygon( *currentMapExtent(), poly );
return poly;
}

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

QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
QgsRectangle thisExtent = *currentMapExtent();
QgsRectangle intersectRect = thisExtent.intersect( &otherExtent );
//get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();

//get current map's extent as a QPolygonF
QPolygonF thisExtent = visibleExtentPolygon();
//intersect the two
QPolygonF intersectExtent = thisExtent.intersected( otherExtent );

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

//construct a polygon corresponding to the intersecting map extent
//need to scale line to dots, rather then mm, since the painter has been scaled to dots
QTransform mapTransform;
QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * rect().width(), dotsPerMM * rect().height() ) );

//workaround QT Bug #21329
thisRectPoly.pop_back();
//create transform from map coordinates to painter coordinates
QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
QPolygonF intersectPolygon;
double x = dotsPerMM * ( intersectRect.xMinimum() - thisExtent.xMinimum() ) / thisExtent.width() * rect().width();
double y = dotsPerMM * ( thisExtent.yMaximum() - intersectRect.yMaximum() ) / thisExtent.height() * rect().height();
double width = dotsPerMM * intersectRect.width() / thisExtent.width() * rect().width();
double height = dotsPerMM * intersectRect.height() / thisExtent.height() * rect().height();
intersectPolygon << QPointF( x, y ) << QPointF( x + width, y ) << QPointF( x + width, y + height ) << QPointF( x, y + height ) << QPointF( x, y );
intersectPolygon = mapTransform.map( intersectExtent );

QList<QPolygonF> rings; //empty list
if ( !mOverviewInverted )
@@ -175,8 +175,11 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
void toggleAtlasPreview();

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

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

/**Returns a polygon representing the current visible map extent, considering map extents and rotation.
* If the map rotation is 0, the result is the same as currentMapExtent
* @returns polygon with the four corner points representing the visible map extent. The points are
* clockwise, starting at the top-left point
* @see currentMapExtent
*/
QPolygonF visibleExtentPolygon() const;

signals:
void extentChanged();

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

/** mapPolygon variant using a given extent */
void mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const;

@@ -39,12 +39,15 @@ class TestQgsComposerMap: public QObject
void grid(); //test if grid and grid annotation works
void crossGrid(); //test if grid "cross" mode works
void overviewMap(); //test if overview map frame works
void overviewMapRotated(); //test if overview map frame works with rotated overview
void overviewMapRotated2(); //test if overview map frame works with rotated map
void overviewMapBlending(); //test if blend modes with overview map frame works
void overviewMapInvert(); //test if invert of overview map frame works
void uniqueId(); //test if map id is adapted when doing copy paste
void zebraStyle(); //test zebra map border style
void overviewMapCenter(); //test if centering of overview map frame works
void worldFileGeneration(); // test world file generation
void mapPolygonVertices(); // test mapPolygon function with no map rotation

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

void TestQgsComposerMap::overviewMapRotated()
{
QgsComposerMap* overviewMap = new QgsComposerMap( mComposition, 20, 130, 70, 70 );
overviewMap->setFrameEnabled( true );
mComposition->addComposerMap( overviewMap );
mComposerMap->setNewExtent( QgsRectangle( 785462.375, 3341423.125, 789262.375, 3343323.125 ) ); //zoom in
mComposerMap->setMapRotation( 30 );
overviewMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3350923.125 ) );
overviewMap->setOverviewFrameMap( mComposerMap->id() );
QgsCompositionChecker checker( "composermap_overview_rotated", mComposition );

bool testResult = checker.testComposition( mReport, 0, 100 );
mComposition->removeComposerItem( overviewMap );
mComposerMap->setMapRotation( 0 );
QVERIFY( testResult );
}

void TestQgsComposerMap::overviewMapRotated2()
{
QgsComposerMap* overviewMap = new QgsComposerMap( mComposition, 20, 130, 70, 70 );
overviewMap->setFrameEnabled( true );
mComposition->addComposerMap( overviewMap );
mComposerMap->setNewExtent( QgsRectangle( 785462.375, 3341423.125, 789262.375, 3343323.125 ) ); //zoom in
overviewMap->setMapRotation( 30 );
overviewMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3350923.125 ) );
overviewMap->setOverviewFrameMap( mComposerMap->id() );
QgsCompositionChecker checker( "composermap_overview_rotated2", mComposition );

bool testResult = checker.testComposition( mReport, 0, 100 );
mComposition->removeComposerItem( overviewMap );
QVERIFY( testResult );
}

void TestQgsComposerMap::overviewMapBlending()
{
QgsComposerMap* overviewMapBlend = new QgsComposerMap( mComposition, 20, 130, 70, 70 );
@@ -292,6 +328,43 @@ void TestQgsComposerMap::worldFileGeneration()
QVERIFY( fabs( d - 2.4136 ) < 0.001 );
QVERIFY( fabs( e + 4.17997 ) < 0.001 );
QVERIFY( fabs( f - 3.34241e+06 ) < 1e+03 );

mComposition->setGenerateWorldFile( false );
mComposerMap->setMapRotation( 0.0 );

}

void TestQgsComposerMap::mapPolygonVertices()
{
mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
QPolygonF visibleExtent = mComposerMap->visibleExtentPolygon();

//vertices should be returned in clockwise order starting at the top-left point
QVERIFY( fabs( visibleExtent[0].x() - 781662.375 ) < 0.001 );
QVERIFY( fabs( visibleExtent[0].y() - 3345223.125 ) < 0.001 );
QVERIFY( fabs( visibleExtent[1].x() - 793062.375 ) < 0.001 );
QVERIFY( fabs( visibleExtent[1].y() - 3345223.125 ) < 0.001 );
QVERIFY( fabs( visibleExtent[2].x() - 793062.375 ) < 0.001 );
QVERIFY( fabs( visibleExtent[2].y() - 3339523.125 ) < 0.001 );
QVERIFY( fabs( visibleExtent[3].x() - 781662.375 ) < 0.001 );
QVERIFY( fabs( visibleExtent[3].y() - 3339523.125 ) < 0.001 );

//now test with rotated map
mComposerMap->setMapRotation( 10 );
visibleExtent = mComposerMap->visibleExtentPolygon();

//vertices should be returned in clockwise order starting at the top-left point
QVERIFY( fabs( visibleExtent[0].x() - 781254.0735015 ) < 0.001 );
QVERIFY( fabs( visibleExtent[0].y() - 3344190.0324834 ) < 0.001 );
QVERIFY( fabs( visibleExtent[1].x() - 792480.881886 ) < 0.001 );
QVERIFY( fabs( visibleExtent[1].y() - 3346169.62171 ) < 0.001 );
QVERIFY( fabs( visibleExtent[2].x() - 793470.676499 ) < 0.001 );
QVERIFY( fabs( visibleExtent[2].y() - 3340556.21752 ) < 0.001 );
QVERIFY( fabs( visibleExtent[3].x() - 782243.868114 ) < 0.001 );
QVERIFY( fabs( visibleExtent[3].y() - 3338576.62829 ) < 0.001 );

mComposerMap->setMapRotation( 0 );

}

QTEST_MAIN( TestQgsComposerMap )
Binary file not shown.
Binary file not shown.

0 comments on commit 01b3d96

Please sign in to comment.