Skip to content

Commit 2d531e5

Browse files
mhugentnyalldawson
authored andcommittedJul 14, 2017
[FEATURE] First experiment with preloading
After main map canvas render is complete, render a separate image for each adjacent map "tile" (in the background). These are shown when panning the map to display a preview of what will be visible when the panning operation ends.
1 parent bf94df8 commit 2d531e5

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed
 

‎src/gui/qgsmapcanvas.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ void QgsMapCanvas::refreshMap()
503503
QgsDebugMsgLevel( "CANVAS refresh!", 3 );
504504

505505
stopRendering(); // if any...
506+
stopPreviewJobs();
506507

507508
//build the expression context
508509
QgsExpressionContext expressionContext;
@@ -624,6 +625,7 @@ void QgsMapCanvas::rendererJobFinished()
624625
p.end();
625626

626627
mMap->setContent( img, imageRect( img, mSettings ) );
628+
startPreviewJobs();
627629
}
628630

629631
// now we are in a slot called from mJob - do not delete it immediately
@@ -634,6 +636,20 @@ void QgsMapCanvas::rendererJobFinished()
634636
emit mapCanvasRefreshed();
635637
}
636638

639+
void QgsMapCanvas::previewJobFinished()
640+
{
641+
QgsMapRendererQImageJob *job = qobject_cast<QgsMapRendererQImageJob *>( sender() );
642+
if ( !job )
643+
{
644+
return;
645+
}
646+
647+
if ( mMap )
648+
{
649+
mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
650+
}
651+
}
652+
637653
QgsRectangle QgsMapCanvas::imageRect( const QImage &img, const QgsMapSettings &mapSettings )
638654
{
639655
// This is a hack to pass QgsMapCanvasItem::setRect what it
@@ -2109,3 +2125,54 @@ const QgsLabelingEngineSettings &QgsMapCanvas::labelingEngineSettings() const
21092125
{
21102126
return mSettings.labelingEngineSettings();
21112127
}
2128+
2129+
void QgsMapCanvas::startPreviewJobs()
2130+
{
2131+
stopPreviewJobs(); //just in case still running
2132+
2133+
QgsRectangle mapRect = mSettings.visibleExtent();
2134+
2135+
for ( int j = 0; j < 3; ++j )
2136+
{
2137+
for ( int i = 0; i < 3; ++i )
2138+
{
2139+
if ( i == 1 && j == 1 )
2140+
{
2141+
continue;
2142+
}
2143+
2144+
2145+
//copy settings, only update extent
2146+
QgsMapSettings jobSettings = mSettings;
2147+
2148+
double dx = ( i - 1 ) * mapRect.width();
2149+
double dy = ( 1 - j ) * mapRect.height();
2150+
QgsRectangle jobExtent = mapRect;
2151+
jobExtent.setXMaximum( jobExtent.xMaximum() + dx );
2152+
jobExtent.setXMinimum( jobExtent.xMinimum() + dx );
2153+
jobExtent.setYMaximum( jobExtent.yMaximum() + dy );
2154+
jobExtent.setYMinimum( jobExtent.yMinimum() + dy );
2155+
2156+
jobSettings.setExtent( jobExtent );
2157+
2158+
QgsMapRendererQImageJob *job = new QgsMapRendererParallelJob( jobSettings );
2159+
mPreviewJobs.append( job );
2160+
connect( job, SIGNAL( finished() ), this, SLOT( previewJobFinished() ) );
2161+
job->start();
2162+
}
2163+
}
2164+
}
2165+
2166+
void QgsMapCanvas::stopPreviewJobs()
2167+
{
2168+
QList< QgsMapRendererQImageJob * >::iterator it = mPreviewJobs.begin();
2169+
for ( ; it != mPreviewJobs.end(); ++it )
2170+
{
2171+
if ( *it )
2172+
{
2173+
( *it )->cancel();
2174+
}
2175+
delete ( *it );
2176+
}
2177+
mPreviewJobs.clear();
2178+
}

‎src/gui/qgsmapcanvas.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
586586
//! called when a renderer job has finished successfully or when it was canceled
587587
void rendererJobFinished();
588588

589+
//! called when a preview job has been finished
590+
void previewJobFinished();
591+
589592
void mapUpdateTimeout();
590593

591594
void refreshMap();
@@ -820,6 +823,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
820823

821824
QgsSnappingUtils *mSnappingUtils = nullptr;
822825

826+
QList< QgsMapRendererQImageJob * > mPreviewJobs;
827+
823828
//! lock the scale, so zooming can be performed using magnication
824829
bool mScaleLocked;
825830

@@ -868,6 +873,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
868873

869874
void setLayersPrivate( const QList<QgsMapLayer *> &layers );
870875

876+
void startPreviewJobs();
877+
void stopPreviewJobs();
878+
871879
friend class TestQgsMapCanvas;
872880

873881
}; // class QgsMapCanvas

‎src/gui/qgsmapcanvasmap.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#include "qgslogger.h"
1717
#include "qgsmapcanvas.h"
1818
#include "qgsmapcanvasmap.h"
19+
#include "qgsmaprendererjob.h"
1920
#include "qgsmapsettings.h"
21+
#include "qgsmaplayer.h"
2022

2123
#include <QPainter>
2224

@@ -30,6 +32,8 @@ QgsMapCanvasMap::QgsMapCanvasMap( QgsMapCanvas *canvas )
3032

3133
void QgsMapCanvasMap::setContent( const QImage &image, const QgsRectangle &rect )
3234
{
35+
mPreviewImages.clear();
36+
3337
mImage = image;
3438

3539
// For true retro fans: this is approximately how the graphics looked like in 1990
@@ -40,16 +44,45 @@ void QgsMapCanvasMap::setContent( const QImage &image, const QgsRectangle &rect
4044
setRect( rect );
4145
}
4246

47+
void QgsMapCanvasMap::addPreviewImage( const QImage &image, const QgsRectangle &rect )
48+
{
49+
mPreviewImages.append( qMakePair( image, rect ) );
50+
update();
51+
}
52+
53+
QRectF QgsMapCanvasMap::boundingRect() const
54+
{
55+
double width = mItemSize.width();
56+
double height = mItemSize.height();
57+
58+
return QRectF( -width, -height, 3 * width, 3 * height );
59+
}
60+
4361
void QgsMapCanvasMap::paint( QPainter *painter )
4462
{
45-
int w = qRound( boundingRect().width() ) - 2, h = qRound( boundingRect().height() ) - 2; // setRect() makes the size +2 :-(
63+
int w = qRound( mItemSize.width() ) - 2, h = qRound( mItemSize.height() ) - 2; // setRect() makes the size +2 :-(
4664
if ( mImage.size() != QSize( w, h ) )
4765
{
4866
QgsDebugMsg( QString( "map paint DIFFERENT SIZE: img %1,%2 item %3,%4" ).arg( mImage.width() ).arg( mImage.height() ).arg( w ).arg( h ) );
4967
// This happens on zoom events when ::paint is called before
5068
// the renderer has completed
5169
}
5270

71+
/*Offset between 0/0 and mRect.xMinimum/mRect.yMinimum.
72+
We need to consider the offset, because mRect is not updated yet and there might be an offset*/
73+
QgsPoint pt = toMapCoordinates( QPoint( 0, 0 ) );
74+
double offsetX = pt.x() - mRect.xMinimum();
75+
double offsetY = pt.y() - mRect.yMaximum();
76+
77+
//draw preview images first
78+
QMap< QgsRectangle, QImage >::const_iterator previewIt = mPreviewImages.constBegin();
79+
for ( ; previewIt != mPreviewImages.constEnd(); ++previewIt )
80+
{
81+
QPointF ul = toCanvasCoordinates( QgsPoint( previewIt.key().xMinimum() + offsetX, previewIt.key().yMaximum() + offsetY ) );
82+
QPointF lr = toCanvasCoordinates( QgsPoint( previewIt.key().xMaximum() + offsetX, previewIt.key().yMinimum() + offsetY ) );
83+
painter->drawImage( QRectF( ul.x(), ul.y(), lr.x() - ul.x(), lr.y() - ul.y() ), previewIt.value(), QRect( 0, 0, previewIt.value().width(), previewIt.value().height() ) );
84+
}
85+
5386
painter->drawImage( QRect( 0, 0, w, h ), mImage );
5487

5588
// For debugging:

‎src/gui/qgsmapcanvasmap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,16 @@ class QgsMapCanvasMap : public QgsMapCanvasItem
4545

4646
virtual void paint( QPainter *painter ) override;
4747

48+
void addPreviewImage( const QImage &image, const QgsRectangle &rect );
49+
50+
QRectF boundingRect() const;
51+
4852
private:
4953

5054
QImage mImage;
55+
56+
//! Preview images for panning. Usually cover area around the rendered image
57+
QList< QPair< QImage, QgsRectangle > > mPreviewImages;
5158
};
5259

5360
/// @endcond

0 commit comments

Comments
 (0)
Please sign in to comment.