[composer] Cache transformed grid lines and intersections to slightly

speed up grid drawing
This commit is contained in:
Nyall Dawson 2014-10-03 23:11:47 +10:00
parent 9e793ebd68
commit 6ec751f634
8 changed files with 192 additions and 77 deletions

View File

@ -223,7 +223,7 @@ class QgsComposerMapGrid : QgsComposerMapItem
/**Draws a grid
* @param painter destination QPainter
*/
void draw( QPainter* painter ) const;
void draw( QPainter* painter );
/**Stores grid state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag

View File

@ -21,7 +21,7 @@ class QgsComposerMapItem : QgsComposerObject
/**Draws the item on to a painter
* @param painter destination QPainter
*/
virtual void draw( QPainter* painter ) const = 0;
virtual void draw( QPainter* painter ) = 0;
/**Stores map item state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag

View File

@ -125,7 +125,7 @@ class QgsComposerMapOverview : QgsComposerMapItem
/**Draws an overview
* @param painter destination QPainter
*/
void draw( QPainter* painter ) const;
void draw( QPainter* painter );
/**Stores overview state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag

View File

@ -144,6 +144,7 @@ double QgsComposerMapGridStack::maxGridExtension() const
QgsComposerMapGrid::QgsComposerMapGrid( const QString& name, QgsComposerMap* map )
: QgsComposerMapItem( name, map )
, mTransformDirty( true )
, mGridStyle( QgsComposerMapGrid::Solid )
, mGridIntervalX( 0.0 )
, mGridIntervalY( 0.0 )
@ -382,6 +383,12 @@ bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocumen
return ok;
}
void QgsComposerMapGrid::setCrs( const QgsCoordinateReferenceSystem &crs )
{
mCRS = crs;
mTransformDirty = true;
}
bool QgsComposerMapGrid::usesAdvancedEffects() const
{
return mBlendMode == QPainter::CompositionMode_SourceOver;
@ -394,13 +401,87 @@ QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const doub
}
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 )
{
return;
}
//has map extent/scale changed?
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
if ( mapPolygon != mPrevMapPolygon )
{
mTransformDirty = true;
mPrevMapPolygon = mapPolygon;
}
if ( mTransformDirty )
{
calculateCRSTransformLines();
}
//draw lines
if ( mGridStyle == QgsComposerMapGrid::Solid )
{
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
{
drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
}
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
{
drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
}
}
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 )
{
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 )
@ -408,34 +489,22 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
return;
}
//x grid lines
QList< QPair< double, QPolygonF > > xGridLines;
xGridLinesCRSTransform( crsBoundingRect, inverseTr, xGridLines );
//calculate x grid lines
mTransformedXLines.clear();
xGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedXLines );
//y grid lines
QList< QPair< double, QPolygonF > > yGridLines;
yGridLinesCRSTransform( crsBoundingRect, inverseTr, yGridLines );
//calculate y grid lines
mTransformedYLines.clear();
yGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedYLines );
if ( mGridStyle == QgsComposerMapGrid::Solid )
if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
{
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin();
for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt )
{
drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
}
//cross or markers style - we also need to calculate intersections of lines
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin();
for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt )
{
drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
}
}
else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers
{
//convert lines to QgsGeometry
//first convert lines to QgsGeometry
QList< QgsGeometry* > yLines;
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin();
for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt )
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
{
QgsPolyline yLine;
for ( int i = 0; i < ( *yGridIt ).second.size(); ++i )
@ -445,8 +514,8 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
yLines << QgsGeometry::fromPolyline( yLine );
}
QList< QgsGeometry* > xLines;
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin();
for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt )
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
{
QgsPolyline xLine;
for ( int i = 0; i < ( *xGridIt ).second.size(); ++i )
@ -456,9 +525,8 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
xLines << QgsGeometry::fromPolyline( xLine );
}
double maxX = mComposerMap->rect().width();
double maxY = mComposerMap->rect().height();
//now, loop through geometries and calculate intersection points
mTransformedIntersections.clear();
QList< QgsGeometry* >::const_iterator yLineIt = yLines.constBegin();
for ( ; yLineIt != yLines.constEnd(); ++yLineIt )
{
@ -473,52 +541,23 @@ void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double
QgsPoint vertex = intersects->vertexAt( i );
while ( vertex != QgsPoint( 0, 0 ) )
{
if ( mGridStyle == QgsComposerMapGrid::Cross )
{
//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 );
}
mTransformedIntersections << vertex;
i = i + 1;
vertex = intersects->vertexAt( i );
}
}
}
//clean up
qDeleteAll( yLines );
yLines.clear();
qDeleteAll( xLines );
xLines.clear();
}
//convert QPolygonF to QLineF to draw grid frames and annotations
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() ) ) );
}
mTransformDirty = false;
}
void QgsComposerMapGrid::draw( QPainter* p ) const
void QgsComposerMapGrid::draw( QPainter* p )
{
if ( !mComposerMap || !mEnabled )
{
@ -536,6 +575,12 @@ void QgsComposerMapGrid::draw( QPainter* p ) const
QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
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
double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
@ -1694,6 +1739,66 @@ double QgsComposerMapGrid::maxExtension() const
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 )
{
switch ( border )

28
src/core/composer/qgscomposermapgrid.h Normal file → Executable file
View File

@ -258,7 +258,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
/**Draws a grid
* @param painter destination QPainter
*/
void draw( QPainter* painter ) const;
void draw( QPainter* painter );
/**Stores grid state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag
@ -278,7 +278,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @param crs coordinate reference system for grid
* @see crs
*/
void setCrs( const QgsCoordinateReferenceSystem& crs ) { mCRS = crs; }
void setCrs( const QgsCoordinateReferenceSystem& crs );
/**Retrieves the CRS for the grid.
* @returns coordinate reference system for grid
@ -315,7 +315,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @param unit unit for grid measurements
* @see units
*/
void setUnits( const GridUnit unit ) { mGridUnit = unit; }
void setUnits( const GridUnit unit );
/**Gets the units used for grid measurements such as the interval
* and offset for grid lines.
@ -330,7 +330,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @see setIntervalY
* @see intervalX
*/
void setIntervalX( const double interval ) { mGridIntervalX = interval; }
void setIntervalX( const double interval );
/**Gets the interval between grid lines in the x-direction. The units
* are retrieved through the units() method.
@ -346,7 +346,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @see setIntervalX
* @see intervalY
*/
void setIntervalY( const double interval ) { mGridIntervalY = interval; }
void setIntervalY( const double interval );
/**Gets the interval between grid lines in the y-direction. The units
* are retrieved through the units() method.
@ -362,7 +362,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @see setOffsetY
* @see offsetX
*/
void setOffsetX( const double offset ) { mGridOffsetX = offset; }
void setOffsetX( const double offset );
/**Gets the offset for grid lines in the x-direction. The units
* are retrieved through the units() method.
@ -378,7 +378,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @see setOffsetX
* @see offsetY
*/
void setOffsetY( const double offset ) { mGridOffsetY = offset; }
void setOffsetY( const double offset );
/**Gets the offset for grid lines in the y-direction. The units
* are retrieved through the units() method.
@ -397,7 +397,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
* @param style desired grid style
* @see style
*/
void setStyle( const GridStyle style ) { mGridStyle = style; }
void setStyle( const GridStyle style );
/**Gets the grid's style, which controls how the grid is drawn
* over the map's contents
@ -741,6 +741,9 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
QgsComposerMapGrid(); //forbidden
/*True if a re-transformation of grid lines is required*/
bool mTransformDirty;
/**Solid or crosses*/
GridStyle mGridStyle;
/**Grid line interval in x-direction (map units)*/
@ -799,6 +802,12 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
QPainter::CompositionMode mBlendMode;
QList< QPair< double, QPolygonF > > mTransformedXLines;
QList< QPair< double, QPolygonF > > mTransformedYLines;
QList< QgsPoint > mTransformedIntersections;
QRectF mPrevPaintRect;
QPolygonF mPrevMapPolygon;
/**Draws the map grid*/
void drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const;
@ -852,7 +861,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
/**Draws grid if CRS is different to map CRS*/
void drawGridCRSTransform( QgsRenderContext &context , double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
QList< QPair< double, QLineF > > &verticalLines ) const;
QList< QPair< double, QLineF > > &verticalLines );
void drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, QList<QPair<double, QLineF> > &horizontalLines, QList<QPair<double, QLineF> > &verticalLines ) const;
@ -868,6 +877,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
void drawGridFrameLineBorder( QPainter *p, BorderSide border ) const;
void calculateCRSTransformLines();
};
#endif // QGSCOMPOSERMAPGRID_H

2
src/core/composer/qgscomposermapitem.h Normal file → Executable file
View File

@ -43,7 +43,7 @@ class CORE_EXPORT QgsComposerMapItem : public QgsComposerObject
/**Draws the item on to a painter
* @param painter destination QPainter
*/
virtual void draw( QPainter* painter ) const = 0;
virtual void draw( QPainter* painter ) = 0;
/**Stores map item state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag

2
src/core/composer/qgscomposermapoverview.cpp Normal file → Executable file
View File

@ -55,7 +55,7 @@ QgsComposerMapOverview::~QgsComposerMapOverview()
delete mFrameSymbol;
}
void QgsComposerMapOverview::draw( QPainter *painter ) const
void QgsComposerMapOverview::draw( QPainter *painter )
{
if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
{

2
src/core/composer/qgscomposermapoverview.h Normal file → Executable file
View File

@ -149,7 +149,7 @@ class CORE_EXPORT QgsComposerMapOverview : public QgsComposerMapItem
/**Draws an overview
* @param painter destination QPainter
*/
void draw( QPainter* painter ) const;
void draw( QPainter* painter );
/**Stores overview state in DOM element
* @param elem is DOM element corresponding to a 'ComposerMap' tag