Skip to content

Commit 6ec751f

Browse files
committed
[composer] Cache transformed grid lines and intersections to slightly
speed up grid drawing
1 parent 9e793eb commit 6ec751f

File tree

8 files changed

+188
-73
lines changed

8 files changed

+188
-73
lines changed

python/core/composer/qgscomposermapgrid.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class QgsComposerMapGrid : QgsComposerMapItem
223223
/**Draws a grid
224224
* @param painter destination QPainter
225225
*/
226-
void draw( QPainter* painter ) const;
226+
void draw( QPainter* painter );
227227

228228
/**Stores grid state in DOM element
229229
* @param elem is DOM element corresponding to a 'ComposerMap' tag

python/core/composer/qgscomposermapitem.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class QgsComposerMapItem : QgsComposerObject
2121
/**Draws the item on to a painter
2222
* @param painter destination QPainter
2323
*/
24-
virtual void draw( QPainter* painter ) const = 0;
24+
virtual void draw( QPainter* painter ) = 0;
2525

2626
/**Stores map item state in DOM element
2727
* @param elem is DOM element corresponding to a 'ComposerMap' tag

python/core/composer/qgscomposermapoverview.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ class QgsComposerMapOverview : QgsComposerMapItem
125125
/**Draws an overview
126126
* @param painter destination QPainter
127127
*/
128-
void draw( QPainter* painter ) const;
128+
void draw( QPainter* painter );
129129

130130
/**Stores overview state in DOM element
131131
* @param elem is DOM element corresponding to a 'ComposerMap' tag

src/core/composer/qgscomposermapgrid.cpp

Lines changed: 163 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ double QgsComposerMapGridStack::maxGridExtension() const
144144

145145
QgsComposerMapGrid::QgsComposerMapGrid( const QString& name, QgsComposerMap* map )
146146
: QgsComposerMapItem( name, map )
147+
, mTransformDirty( true )
147148
, mGridStyle( QgsComposerMapGrid::Solid )
148149
, mGridIntervalX( 0.0 )
149150
, mGridIntervalY( 0.0 )
@@ -382,6 +383,12 @@ bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocumen
382383
return ok;
383384
}
384385

386+
void QgsComposerMapGrid::setCrs( const QgsCoordinateReferenceSystem &crs )
387+
{
388+
mCRS = crs;
389+
mTransformDirty = true;
390+
}
391+
385392
bool QgsComposerMapGrid::usesAdvancedEffects() const
386393
{
387394
return mBlendMode == QPainter::CompositionMode_SourceOver;
@@ -394,48 +401,110 @@ QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const doub
394401
}
395402

396403
void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
397-
QList< QPair< double, QLineF > > &verticalLines ) const
404+
QList< QPair< double, QLineF > > &verticalLines )
398405
{
399406
if ( !mComposerMap || !mEnabled )
400407
{
401408
return;
402409
}
403410

404-
QgsRectangle crsBoundingRect;
405-
QgsCoordinateTransform inverseTr;
406-
if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
411+
//has map extent/scale changed?
412+
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
413+
if ( mapPolygon != mPrevMapPolygon )
407414
{
408-
return;
415+
mTransformDirty = true;
416+
mPrevMapPolygon = mapPolygon;
409417
}
410418

411-
//x grid lines
412-
QList< QPair< double, QPolygonF > > xGridLines;
413-
xGridLinesCRSTransform( crsBoundingRect, inverseTr, xGridLines );
414-
415-
//y grid lines
416-
QList< QPair< double, QPolygonF > > yGridLines;
417-
yGridLinesCRSTransform( crsBoundingRect, inverseTr, yGridLines );
419+
if ( mTransformDirty )
420+
{
421+
calculateCRSTransformLines();
422+
}
418423

424+
//draw lines
419425
if ( mGridStyle == QgsComposerMapGrid::Solid )
420426
{
421-
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin();
422-
for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt )
427+
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
428+
for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
423429
{
424430
drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
425431
}
426432

427-
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin();
428-
for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt )
433+
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
434+
for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
429435
{
430436
drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
431437
}
432438
}
433-
else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers
439+
else if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
440+
{
441+
double maxX = mComposerMap->rect().width();
442+
double maxY = mComposerMap->rect().height();
443+
444+
QList< QgsPoint >::const_iterator intersectionIt = mTransformedIntersections.constBegin();
445+
for ( ; intersectionIt != mTransformedIntersections.constEnd(); ++intersectionIt )
446+
{
447+
double x = intersectionIt->x();
448+
double y = intersectionIt->y();
449+
if ( mGridStyle == QgsComposerMapGrid::Cross )
450+
{
451+
//ensure that crosses don't overshoot the map item bounds
452+
QLineF line1 = QLineF( x - mCrossLength, y, x + mCrossLength, y );
453+
line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
454+
line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
455+
QLineF line2 = QLineF( x, y - mCrossLength, x, y + mCrossLength );
456+
line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
457+
line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();
458+
459+
//draw line using coordinates scaled to dots
460+
drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
461+
drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
462+
}
463+
else if ( mGridStyle == QgsComposerMapGrid::Markers )
464+
{
465+
drawGridMarker( QPointF( x, y ) * dotsPerMM , context );
466+
}
467+
}
468+
}
469+
470+
//convert QPolygonF to QLineF to draw grid frames and annotations
471+
QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = mTransformedYLines.constBegin();
472+
for ( ; yGridLineIt != mTransformedYLines.constEnd(); ++yGridLineIt )
434473
{
435-
//convert lines to QgsGeometry
474+
verticalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
475+
}
476+
QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = mTransformedXLines.constBegin();
477+
for ( ; xGridLineIt != mTransformedXLines.constEnd(); ++xGridLineIt )
478+
{
479+
horizontalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
480+
}
481+
}
482+
483+
void QgsComposerMapGrid::calculateCRSTransformLines()
484+
{
485+
QgsRectangle crsBoundingRect;
486+
QgsCoordinateTransform inverseTr;
487+
if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
488+
{
489+
return;
490+
}
491+
492+
//calculate x grid lines
493+
mTransformedXLines.clear();
494+
xGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedXLines );
495+
496+
//calculate y grid lines
497+
mTransformedYLines.clear();
498+
yGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedYLines );
499+
500+
if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
501+
{
502+
//cross or markers style - we also need to calculate intersections of lines
503+
504+
//first convert lines to QgsGeometry
436505
QList< QgsGeometry* > yLines;
437-
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin();
438-
for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt )
506+
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
507+
for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
439508
{
440509
QgsPolyline yLine;
441510
for ( int i = 0; i < ( *yGridIt ).second.size(); ++i )
@@ -445,8 +514,8 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
445514
yLines << QgsGeometry::fromPolyline( yLine );
446515
}
447516
QList< QgsGeometry* > xLines;
448-
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin();
449-
for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt )
517+
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
518+
for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
450519
{
451520
QgsPolyline xLine;
452521
for ( int i = 0; i < ( *xGridIt ).second.size(); ++i )
@@ -456,9 +525,8 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
456525
xLines << QgsGeometry::fromPolyline( xLine );
457526
}
458527

459-
double maxX = mComposerMap->rect().width();
460-
double maxY = mComposerMap->rect().height();
461-
528+
//now, loop through geometries and calculate intersection points
529+
mTransformedIntersections.clear();
462530
QList< QgsGeometry* >::const_iterator yLineIt = yLines.constBegin();
463531
for ( ; yLineIt != yLines.constEnd(); ++yLineIt )
464532
{
@@ -473,52 +541,23 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
473541
QgsPoint vertex = intersects->vertexAt( i );
474542
while ( vertex != QgsPoint( 0, 0 ) )
475543
{
476-
if ( mGridStyle == QgsComposerMapGrid::Cross )
477-
{
478-
//ensure that crosses don't overshoot the map item bounds
479-
QLineF line1 = QLineF( vertex.x() - mCrossLength, vertex.y(), vertex.x() + mCrossLength, vertex.y() );
480-
line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
481-
line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
482-
QLineF line2 = QLineF( vertex.x() , vertex.y() - mCrossLength, vertex.x(), vertex.y() + mCrossLength );
483-
line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
484-
line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();
485-
486-
//draw line using coordinates scaled to dots
487-
drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
488-
drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
489-
}
490-
else if ( mGridStyle == QgsComposerMapGrid::Markers )
491-
{
492-
drawGridMarker( QPointF( vertex.x(), vertex.y() ) * dotsPerMM , context );
493-
}
494-
544+
mTransformedIntersections << vertex;
495545
i = i + 1;
496546
vertex = intersects->vertexAt( i );
497547
}
498548
}
499549
}
500-
550+
//clean up
501551
qDeleteAll( yLines );
502552
yLines.clear();
503553
qDeleteAll( xLines );
504554
xLines.clear();
505555
}
506556

507-
//convert QPolygonF to QLineF to draw grid frames and annotations
508-
QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = yGridLines.constBegin();
509-
for ( ; yGridLineIt != yGridLines.constEnd(); ++yGridLineIt )
510-
{
511-
verticalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
512-
}
513-
QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = xGridLines.constBegin();
514-
for ( ; xGridLineIt != xGridLines.constEnd(); ++xGridLineIt )
515-
{
516-
horizontalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
517-
}
518-
557+
mTransformDirty = false;
519558
}
520559

521-
void QgsComposerMapGrid::draw( QPainter* p ) const
560+
void QgsComposerMapGrid::draw( QPainter* p )
522561
{
523562
if ( !mComposerMap || !mEnabled )
524563
{
@@ -536,6 +575,12 @@ void QgsComposerMapGrid::draw( QPainter* p ) const
536575

537576
QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
538577
p->setClipRect( thisPaintRect );
578+
if ( thisPaintRect != mPrevPaintRect )
579+
{
580+
//rect has changed, so need to recalculate transform
581+
mTransformDirty = true;
582+
mPrevPaintRect = thisPaintRect;
583+
}
539584

540585
//setup painter scaling to dots so that raster symbology is drawn to scale
541586
double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
@@ -1694,6 +1739,66 @@ double QgsComposerMapGrid::maxExtension() const
16941739
return maxExtension + mAnnotationFrameDistance + gridFrameDist;
16951740
}
16961741

1742+
void QgsComposerMapGrid::setUnits( const QgsComposerMapGrid::GridUnit unit )
1743+
{
1744+
if ( unit == mGridUnit )
1745+
{
1746+
return;
1747+
}
1748+
mGridUnit = unit;
1749+
mTransformDirty = true;
1750+
}
1751+
1752+
void QgsComposerMapGrid::setIntervalX( const double interval )
1753+
{
1754+
if ( interval == mGridIntervalX )
1755+
{
1756+
return;
1757+
}
1758+
mGridIntervalX = interval;
1759+
mTransformDirty = true;
1760+
}
1761+
1762+
void QgsComposerMapGrid::setIntervalY( const double interval )
1763+
{
1764+
if ( interval == mGridIntervalY )
1765+
{
1766+
return;
1767+
}
1768+
mGridIntervalY = interval;
1769+
mTransformDirty = true;
1770+
}
1771+
1772+
void QgsComposerMapGrid::setOffsetX( const double offset )
1773+
{
1774+
if ( offset == mGridOffsetX )
1775+
{
1776+
return;
1777+
}
1778+
mGridOffsetX = offset;
1779+
mTransformDirty = true;
1780+
}
1781+
1782+
void QgsComposerMapGrid::setOffsetY( const double offset )
1783+
{
1784+
if ( offset == mGridOffsetY )
1785+
{
1786+
return;
1787+
}
1788+
mGridOffsetY = offset;
1789+
mTransformDirty = true;
1790+
}
1791+
1792+
void QgsComposerMapGrid::setStyle( const QgsComposerMapGrid::GridStyle style )
1793+
{
1794+
if ( style == mGridStyle )
1795+
{
1796+
return;
1797+
}
1798+
mGridStyle = style;
1799+
mTransformDirty = true;
1800+
}
1801+
16971802
void QgsComposerMapGrid::setAnnotationDirection( const QgsComposerMapGrid::AnnotationDirection direction, const QgsComposerMapGrid::BorderSide border )
16981803
{
16991804
switch ( border )

0 commit comments

Comments
 (0)