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 01b3d96
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 24 deletions.
@@ -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 )
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 01b3d96

Please sign in to comment.