Skip to content

Commit

Permalink
[composer] Cache transformed grid lines and intersections to slightly
Browse files Browse the repository at this point in the history
speed up grid drawing
  • Loading branch information
nyalldawson committed Oct 3, 2014
1 parent 9e793eb commit 6ec751f
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 73 deletions.
2 changes: 1 addition & 1 deletion python/core/composer/qgscomposermapgrid.sip
Expand Up @@ -223,7 +223,7 @@ class QgsComposerMapGrid : QgsComposerMapItem
/**Draws a grid /**Draws a grid
* @param painter destination QPainter * @param painter destination QPainter
*/ */
void draw( QPainter* painter ) const; void draw( QPainter* painter );


/**Stores grid state in DOM element /**Stores grid state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag * @param elem is DOM element corresponding to a 'ComposerMap' tag
Expand Down
2 changes: 1 addition & 1 deletion python/core/composer/qgscomposermapitem.sip
Expand Up @@ -21,7 +21,7 @@ class QgsComposerMapItem : QgsComposerObject
/**Draws the item on to a painter /**Draws the item on to a painter
* @param painter destination QPainter * @param painter destination QPainter
*/ */
virtual void draw( QPainter* painter ) const = 0; virtual void draw( QPainter* painter ) = 0;


/**Stores map item state in DOM element /**Stores map item state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag * @param elem is DOM element corresponding to a 'ComposerMap' tag
Expand Down
2 changes: 1 addition & 1 deletion python/core/composer/qgscomposermapoverview.sip
Expand Up @@ -125,7 +125,7 @@ class QgsComposerMapOverview : QgsComposerMapItem
/**Draws an overview /**Draws an overview
* @param painter destination QPainter * @param painter destination QPainter
*/ */
void draw( QPainter* painter ) const; void draw( QPainter* painter );


/**Stores overview state in DOM element /**Stores overview state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag * @param elem is DOM element corresponding to a 'ComposerMap' tag
Expand Down
221 changes: 163 additions & 58 deletions src/core/composer/qgscomposermapgrid.cpp
Expand Up @@ -144,6 +144,7 @@ double QgsComposerMapGridStack::maxGridExtension() const


QgsComposerMapGrid::QgsComposerMapGrid( const QString& name, QgsComposerMap* map ) QgsComposerMapGrid::QgsComposerMapGrid( const QString& name, QgsComposerMap* map )
: QgsComposerMapItem( name, map ) : QgsComposerMapItem( name, map )
, mTransformDirty( true )
, mGridStyle( QgsComposerMapGrid::Solid ) , mGridStyle( QgsComposerMapGrid::Solid )
, mGridIntervalX( 0.0 ) , mGridIntervalX( 0.0 )
, mGridIntervalY( 0.0 ) , mGridIntervalY( 0.0 )
Expand Down Expand Up @@ -382,6 +383,12 @@ bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocumen
return ok; return ok;
} }


void QgsComposerMapGrid::setCrs( const QgsCoordinateReferenceSystem &crs )
{
mCRS = crs;
mTransformDirty = true;
}

bool QgsComposerMapGrid::usesAdvancedEffects() const bool QgsComposerMapGrid::usesAdvancedEffects() const
{ {
return mBlendMode == QPainter::CompositionMode_SourceOver; return mBlendMode == QPainter::CompositionMode_SourceOver;
Expand All @@ -394,48 +401,110 @@ QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const doub
} }


void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines, void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
QList< QPair< double, QLineF > > &verticalLines ) const QList< QPair< double, QLineF > > &verticalLines )
{ {
if ( !mComposerMap || !mEnabled ) if ( !mComposerMap || !mEnabled )
{ {
return; return;
} }


QgsRectangle crsBoundingRect; //has map extent/scale changed?
QgsCoordinateTransform inverseTr; QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 ) if ( mapPolygon != mPrevMapPolygon )
{ {
return; mTransformDirty = true;
mPrevMapPolygon = mapPolygon;
} }


//x grid lines if ( mTransformDirty )
QList< QPair< double, QPolygonF > > xGridLines; {
xGridLinesCRSTransform( crsBoundingRect, inverseTr, xGridLines ); calculateCRSTransformLines();

}
//y grid lines
QList< QPair< double, QPolygonF > > yGridLines;
yGridLinesCRSTransform( crsBoundingRect, inverseTr, yGridLines );


//draw lines
if ( mGridStyle == QgsComposerMapGrid::Solid ) if ( mGridStyle == QgsComposerMapGrid::Solid )
{ {
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin(); QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt ) for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
{ {
drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context ); drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
} }


QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin(); QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt ) for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
{ {
drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context ); drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
} }
} }
else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers else if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
{
double maxX = mComposerMap->rect().width();
double maxY = mComposerMap->rect().height();

QList< QgsPoint >::const_iterator intersectionIt = mTransformedIntersections.constBegin();
for ( ; intersectionIt != mTransformedIntersections.constEnd(); ++intersectionIt )
{
double x = intersectionIt->x();
double y = intersectionIt->y();
if ( mGridStyle == QgsComposerMapGrid::Cross )
{
//ensure that crosses don't overshoot the map item bounds
QLineF line1 = QLineF( x - mCrossLength, y, x + mCrossLength, y );
line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
QLineF line2 = QLineF( x, y - mCrossLength, x, y + mCrossLength );
line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();

//draw line using coordinates scaled to dots
drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
}
else if ( mGridStyle == QgsComposerMapGrid::Markers )
{
drawGridMarker( QPointF( x, y ) * dotsPerMM , context );
}
}
}

//convert QPolygonF to QLineF to draw grid frames and annotations
QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = mTransformedYLines.constBegin();
for ( ; yGridLineIt != mTransformedYLines.constEnd(); ++yGridLineIt )
{ {
//convert lines to QgsGeometry verticalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
}
QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = mTransformedXLines.constBegin();
for ( ; xGridLineIt != mTransformedXLines.constEnd(); ++xGridLineIt )
{
horizontalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
}
}

void QgsComposerMapGrid::calculateCRSTransformLines()
{
QgsRectangle crsBoundingRect;
QgsCoordinateTransform inverseTr;
if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
{
return;
}

//calculate x grid lines
mTransformedXLines.clear();
xGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedXLines );

//calculate y grid lines
mTransformedYLines.clear();
yGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedYLines );

if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
{
//cross or markers style - we also need to calculate intersections of lines

//first convert lines to QgsGeometry
QList< QgsGeometry* > yLines; QList< QgsGeometry* > yLines;
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin(); QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt ) for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
{ {
QgsPolyline yLine; QgsPolyline yLine;
for ( int i = 0; i < ( *yGridIt ).second.size(); ++i ) for ( int i = 0; i < ( *yGridIt ).second.size(); ++i )
Expand All @@ -445,8 +514,8 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
yLines << QgsGeometry::fromPolyline( yLine ); yLines << QgsGeometry::fromPolyline( yLine );
} }
QList< QgsGeometry* > xLines; QList< QgsGeometry* > xLines;
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin(); QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt ) for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
{ {
QgsPolyline xLine; QgsPolyline xLine;
for ( int i = 0; i < ( *xGridIt ).second.size(); ++i ) for ( int i = 0; i < ( *xGridIt ).second.size(); ++i )
Expand All @@ -456,9 +525,8 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
xLines << QgsGeometry::fromPolyline( xLine ); xLines << QgsGeometry::fromPolyline( xLine );
} }


double maxX = mComposerMap->rect().width(); //now, loop through geometries and calculate intersection points
double maxY = mComposerMap->rect().height(); mTransformedIntersections.clear();

QList< QgsGeometry* >::const_iterator yLineIt = yLines.constBegin(); QList< QgsGeometry* >::const_iterator yLineIt = yLines.constBegin();
for ( ; yLineIt != yLines.constEnd(); ++yLineIt ) for ( ; yLineIt != yLines.constEnd(); ++yLineIt )
{ {
Expand All @@ -473,52 +541,23 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
QgsPoint vertex = intersects->vertexAt( i ); QgsPoint vertex = intersects->vertexAt( i );
while ( vertex != QgsPoint( 0, 0 ) ) while ( vertex != QgsPoint( 0, 0 ) )
{ {
if ( mGridStyle == QgsComposerMapGrid::Cross ) mTransformedIntersections << vertex;
{
//ensure that crosses don't overshoot the map item bounds
QLineF line1 = QLineF( vertex.x() - mCrossLength, vertex.y(), vertex.x() + mCrossLength, vertex.y() );
line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
QLineF line2 = QLineF( vertex.x() , vertex.y() - mCrossLength, vertex.x(), vertex.y() + mCrossLength );
line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();

//draw line using coordinates scaled to dots
drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
}
else if ( mGridStyle == QgsComposerMapGrid::Markers )
{
drawGridMarker( QPointF( vertex.x(), vertex.y() ) * dotsPerMM , context );
}

i = i + 1; i = i + 1;
vertex = intersects->vertexAt( i ); vertex = intersects->vertexAt( i );
} }
} }
} }

//clean up
qDeleteAll( yLines ); qDeleteAll( yLines );
yLines.clear(); yLines.clear();
qDeleteAll( xLines ); qDeleteAll( xLines );
xLines.clear(); xLines.clear();
} }


//convert QPolygonF to QLineF to draw grid frames and annotations mTransformDirty = false;
QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = yGridLines.constBegin();
for ( ; yGridLineIt != yGridLines.constEnd(); ++yGridLineIt )
{
verticalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
}
QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = xGridLines.constBegin();
for ( ; xGridLineIt != xGridLines.constEnd(); ++xGridLineIt )
{
horizontalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
}

} }


void QgsComposerMapGrid::draw( QPainter* p ) const void QgsComposerMapGrid::draw( QPainter* p )
{ {
if ( !mComposerMap || !mEnabled ) if ( !mComposerMap || !mEnabled )
{ {
Expand All @@ -536,6 +575,12 @@ void QgsComposerMapGrid::draw( QPainter* p ) const


QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() ); QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
p->setClipRect( thisPaintRect ); p->setClipRect( thisPaintRect );
if ( thisPaintRect != mPrevPaintRect )
{
//rect has changed, so need to recalculate transform
mTransformDirty = true;
mPrevPaintRect = thisPaintRect;
}


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


void QgsComposerMapGrid::setUnits( const QgsComposerMapGrid::GridUnit unit )
{
if ( unit == mGridUnit )
{
return;
}
mGridUnit = unit;
mTransformDirty = true;
}

void QgsComposerMapGrid::setIntervalX( const double interval )
{
if ( interval == mGridIntervalX )
{
return;
}
mGridIntervalX = interval;
mTransformDirty = true;
}

void QgsComposerMapGrid::setIntervalY( const double interval )
{
if ( interval == mGridIntervalY )
{
return;
}
mGridIntervalY = interval;
mTransformDirty = true;
}

void QgsComposerMapGrid::setOffsetX( const double offset )
{
if ( offset == mGridOffsetX )
{
return;
}
mGridOffsetX = offset;
mTransformDirty = true;
}

void QgsComposerMapGrid::setOffsetY( const double offset )
{
if ( offset == mGridOffsetY )
{
return;
}
mGridOffsetY = offset;
mTransformDirty = true;
}

void QgsComposerMapGrid::setStyle( const QgsComposerMapGrid::GridStyle style )
{
if ( style == mGridStyle )
{
return;
}
mGridStyle = style;
mTransformDirty = true;
}

void QgsComposerMapGrid::setAnnotationDirection( const QgsComposerMapGrid::AnnotationDirection direction, const QgsComposerMapGrid::BorderSide border ) void QgsComposerMapGrid::setAnnotationDirection( const QgsComposerMapGrid::AnnotationDirection direction, const QgsComposerMapGrid::BorderSide border )
{ {
switch ( border ) switch ( border )
Expand Down

0 comments on commit 6ec751f

Please sign in to comment.