Skip to content

Commit b242324

Browse files
committed
[composer] Use intersection rather than clip for transformed grids
Previous behaviour was to clip transformed grid lines to the visible map extent. This caused problems if a map item had no border (a solid line would be shown along the map extent), and also meant that reprojected lines which crossed out of the map extent and back in again did not have annotations or grid frame markings shown. Also implement an improved logic for detecting the map frame side for annotations.
1 parent abf0087 commit b242324

File tree

4 files changed

+82
-46
lines changed

4 files changed

+82
-46
lines changed

src/core/composer/qgscomposermapgrid.cpp

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,11 +1615,15 @@ int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const
16151615
}
16161616
crossed180 = false;
16171617

1618-
gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1619-
if ( gridLine.size() > 0 )
1618+
QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1619+
QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1620+
for ( ; lineIt != lineSegments.constEnd(); lineIt ++ )
16201621
{
1621-
lines.append( qMakePair( currentLevel, gridLine ) );
1622-
gridLineCount++;
1622+
if (( *lineIt ).size() > 0 )
1623+
{
1624+
lines.append( qMakePair( currentLevel, *lineIt ) );
1625+
gridLineCount++;
1626+
}
16231627
}
16241628
currentLevel -= mGridIntervalY;
16251629
}
@@ -1677,11 +1681,15 @@ int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const
16771681
currentY += step;
16781682
}
16791683
//clip grid line to map polygon
1680-
gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1681-
if ( gridLine.size() > 0 )
1684+
QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1685+
QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1686+
for ( ; lineIt != lineSegments.constEnd(); lineIt ++ )
16821687
{
1683-
lines.append( qMakePair( currentLevel, gridLine ) );
1684-
gridLineCount++;
1688+
if (( *lineIt ).size() > 0 )
1689+
{
1690+
lines.append( qMakePair( currentLevel, *lineIt ) );
1691+
gridLineCount++;
1692+
}
16851693
}
16861694
currentLevel += mGridIntervalX;
16871695
if ( crosses180 && currentLevel > 180.0 )
@@ -1775,26 +1783,31 @@ bool QgsComposerMapGrid::shouldShowDivisionForDisplayMode( const QgsComposerMapG
17751783
|| ( mode == QgsComposerMapGrid::LongitudeOnly && coordinate == QgsComposerMapGrid::Longitude );
17761784
}
17771785

1786+
bool sortByDistance( const QPair<double, QgsComposerMapGrid::BorderSide>& a, const QPair<double, QgsComposerMapGrid::BorderSide>& b )
1787+
{
1788+
return a.first < b.first;
1789+
}
1790+
17781791
QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPointF& p, const AnnotationCoordinate coordinateType ) const
17791792
{
17801793
if ( !mComposerMap )
17811794
{
17821795
return QgsComposerMapGrid::Left;
17831796
}
17841797

1785-
double framePenWidth = mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.000000001;
1798+
double tolerance = qMax( mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.0, 1.0 );
17861799

17871800
//check for corner coordinates
1788-
if (( p.y() <= framePenWidth && p.x() <= framePenWidth ) // top left
1789-
|| ( p.y() <= framePenWidth && p.x() >= ( mComposerMap->rect().width() - framePenWidth ) ) //top right
1790-
|| ( p.y() >= ( mComposerMap->rect().height() - framePenWidth ) && p.x() <= framePenWidth ) //bottom left
1791-
|| ( p.y() >= ( mComposerMap->rect().height() - framePenWidth ) && p.x() >= ( mComposerMap->rect().width() - framePenWidth ) ) //bottom right
1801+
if (( p.y() <= tolerance && p.x() <= tolerance ) // top left
1802+
|| ( p.y() <= tolerance && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //top right
1803+
|| ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() <= tolerance ) //bottom left
1804+
|| ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //bottom right
17921805
)
17931806
{
17941807
//coordinate is in corner - fall back to preferred side for coordinate type
17951808
if ( coordinateType == QgsComposerMapGrid::Latitude )
17961809
{
1797-
if ( p.x() <= framePenWidth )
1810+
if ( p.x() <= tolerance )
17981811
{
17991812
return QgsComposerMapGrid::Left;
18001813
}
@@ -1805,7 +1818,7 @@ QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPo
18051818
}
18061819
else
18071820
{
1808-
if ( p.y() <= framePenWidth )
1821+
if ( p.y() <= tolerance )
18091822
{
18101823
return QgsComposerMapGrid::Top;
18111824
}
@@ -1816,23 +1829,15 @@ QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPo
18161829
}
18171830
}
18181831

1819-
//otherwise, guess side based on point
1820-
if ( p.y() <= framePenWidth )
1821-
{
1822-
return QgsComposerMapGrid::Top;
1823-
}
1824-
else if ( p.x() <= framePenWidth )
1825-
{
1826-
return QgsComposerMapGrid::Left;
1827-
}
1828-
else if ( p.x() >= ( mComposerMap->rect().width() - framePenWidth ) )
1829-
{
1830-
return QgsComposerMapGrid::Right;
1831-
}
1832-
else
1833-
{
1834-
return QgsComposerMapGrid::Bottom;
1835-
}
1832+
//otherwise, guess side based on closest map side to point
1833+
QList< QPair<double, QgsComposerMapGrid::BorderSide > > distanceToSide;
1834+
distanceToSide << qMakePair( p.x(), QgsComposerMapGrid::Left );
1835+
distanceToSide << qMakePair( mComposerMap->rect().width() - p.x(), QgsComposerMapGrid::Right );
1836+
distanceToSide << qMakePair( p.y(), QgsComposerMapGrid::Top );
1837+
distanceToSide << qMakePair( mComposerMap->rect().height() - p.y(), QgsComposerMapGrid::Bottom );
1838+
1839+
qSort( distanceToSide.begin(), distanceToSide.end(), sortByDistance );
1840+
return distanceToSide.at( 0 ).second;
18361841
}
18371842

18381843
void QgsComposerMapGrid::setLineSymbol( QgsLineSymbolV2* symbol )
@@ -2268,21 +2273,25 @@ int QgsComposerMapGrid::crsGridParams( QgsRectangle& crsRect, QgsCoordinateTrans
22682273
return 0;
22692274
}
22702275

2271-
QPolygonF QgsComposerMapGrid::trimLineToMap( const QPolygonF& line, const QgsRectangle& rect )
2276+
QList<QPolygonF> QgsComposerMapGrid::trimLinesToMap( const QPolygonF& line, const QgsRectangle& rect )
22722277
{
2273-
QgsPolyline polyLine;
2274-
QPolygonF::const_iterator lineIt = line.constBegin();
2275-
for ( ; lineIt != line.constEnd(); ++lineIt )
2278+
QgsGeometry* lineGeom = QgsGeometry::fromQPolygonF( line );
2279+
QgsGeometry* rectGeom = QgsGeometry::fromRect( rect );
2280+
2281+
QgsGeometry* intersected = lineGeom->intersection( rectGeom );
2282+
QList<QgsGeometry*> intersectedParts = intersected->asGeometryCollection();
2283+
2284+
QList<QPolygonF> trimmedLines;
2285+
QList<QgsGeometry*>::const_iterator geomIt = intersectedParts.constBegin();
2286+
for ( ; geomIt != intersectedParts.constEnd(); geomIt++ )
22762287
{
2277-
polyLine.append( QgsPoint( lineIt->x(), lineIt->y() ) );
2288+
trimmedLines << ( *geomIt )->asQPolygonF();
22782289
}
22792290

2280-
QgsGeometry* geom = QgsGeometry::fromPolyline( polyLine );
2281-
2282-
QPolygonF clippedLine;
2283-
QgsClipper::clippedLineWKB( geom->asWkb(), rect, clippedLine );
2284-
delete geom;
2285-
return clippedLine;
2291+
qDeleteAll( intersectedParts );
2292+
intersectedParts.clear();
2293+
delete intersected;
2294+
delete lineGeom;
2295+
delete rectGeom;
2296+
return trimmedLines;
22862297
}
2287-
2288-

src/core/composer/qgscomposermapgrid.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
931931
/**Get parameters for drawing grid in CRS different to map CRS*/
932932
int crsGridParams( QgsRectangle& crsRect, QgsCoordinateTransform& inverseTransform ) const;
933933

934-
static QPolygonF trimLineToMap( const QPolygonF& line, const QgsRectangle& rect );
934+
static QList<QPolygonF> trimLinesToMap( const QPolygonF &line, const QgsRectangle &rect );
935935

936936
QPolygonF scalePolygon( const QPolygonF &polygon, const double scale ) const;
937937

tests/src/core/testqgscomposermapgrid.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class TestQgsComposerMapGrid: public QObject
3535
void init();// will be called before each testfunction is executed.
3636
void cleanup();// will be called after every testfunction.
3737
void grid(); //test if grid and grid annotation works
38+
void reprojected(); //test if reprojected grid works
3839
void crossGrid(); //test if grid "cross" mode works
3940
void markerGrid(); //test if grid "marker" mode works
4041
void frameOnly(); //test if grid "frame/annotation" mode works
@@ -128,6 +129,31 @@ void TestQgsComposerMapGrid::grid()
128129
QVERIFY( testResult );
129130
}
130131

132+
void TestQgsComposerMapGrid::reprojected()
133+
{
134+
mComposerMap->setNewExtent( QgsRectangle( -243577.565, 2939084.773, 1215622.435, 3668684.773 ) );
135+
QgsCoordinateReferenceSystem geographic = QgsCoordinateReferenceSystem( 4326 );
136+
mComposerMap->grid()->setCrs( geographic );
137+
mComposerMap->grid()->setEnabled( true );
138+
mComposerMap->grid()->setIntervalX( 1 );
139+
mComposerMap->grid()->setIntervalY( 1 );
140+
mComposerMap->grid()->setAnnotationEnabled( false );
141+
mComposerMap->grid()->setGridLineColor( QColor( 0, 0, 0 ) );
142+
mComposerMap->grid()->setGridLineWidth( 0.5 );
143+
mComposerMap->grid()->setBlendMode( QPainter::CompositionMode_SourceOver );
144+
mComposerMap->grid()->setFrameStyle( QgsComposerMapGrid::ExteriorTicks );
145+
mComposerMap->grid()->setFrameWidth( 10 );
146+
mComposerMap->setFrameEnabled( false );
147+
QgsCompositionChecker checker( "composermap_gridreprojected", mComposition );
148+
149+
bool testResult = checker.testComposition( mReport, 0, 0 );
150+
mComposerMap->grid()->setEnabled( false );
151+
mComposerMap->grid()->setCrs( mMapSettings.destinationCrs() );
152+
mComposerMap->grid()->setFrameStyle( QgsComposerMapGrid::NoFrame );
153+
mComposerMap->setFrameEnabled( true );
154+
QVERIFY( testResult );
155+
}
156+
131157
void TestQgsComposerMapGrid::crossGrid()
132158
{
133159
mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
@@ -177,6 +203,7 @@ void TestQgsComposerMapGrid::frameOnly()
177203
mComposerMap->grid()->setAnnotationEnabled( false );
178204
//set a frame for testing
179205
mComposerMap->grid()->setFrameStyle( QgsComposerMapGrid::Zebra );
206+
mComposerMap->grid()->setFrameWidth( 2.0 );
180207
mComposerMap->grid()->setFramePenSize( 0.5 );
181208
mComposerMap->grid()->setBlendMode( QPainter::CompositionMode_SourceOver );
182209
QgsCompositionChecker checker( "composermap_gridframeonly", mComposition );

0 commit comments

Comments
 (0)