Skip to content

Commit

Permalink
[FEATURE] First experiment with preloading
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mhugent authored and nyalldawson committed Jul 14, 2017
1 parent bf94df8 commit 2d531e5
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 1 deletion.
67 changes: 67 additions & 0 deletions src/gui/qgsmapcanvas.cpp
Expand Up @@ -503,6 +503,7 @@ void QgsMapCanvas::refreshMap()
QgsDebugMsgLevel( "CANVAS refresh!", 3 ); QgsDebugMsgLevel( "CANVAS refresh!", 3 );


stopRendering(); // if any... stopRendering(); // if any...
stopPreviewJobs();


//build the expression context //build the expression context
QgsExpressionContext expressionContext; QgsExpressionContext expressionContext;
Expand Down Expand Up @@ -624,6 +625,7 @@ void QgsMapCanvas::rendererJobFinished()
p.end(); p.end();


mMap->setContent( img, imageRect( img, mSettings ) ); mMap->setContent( img, imageRect( img, mSettings ) );
startPreviewJobs();
} }


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


void QgsMapCanvas::previewJobFinished()
{
QgsMapRendererQImageJob *job = qobject_cast<QgsMapRendererQImageJob *>( sender() );
if ( !job )
{
return;
}

if ( mMap )
{
mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
}
}

QgsRectangle QgsMapCanvas::imageRect( const QImage &img, const QgsMapSettings &mapSettings ) QgsRectangle QgsMapCanvas::imageRect( const QImage &img, const QgsMapSettings &mapSettings )
{ {
// This is a hack to pass QgsMapCanvasItem::setRect what it // This is a hack to pass QgsMapCanvasItem::setRect what it
Expand Down Expand Up @@ -2109,3 +2125,54 @@ const QgsLabelingEngineSettings &QgsMapCanvas::labelingEngineSettings() const
{ {
return mSettings.labelingEngineSettings(); return mSettings.labelingEngineSettings();
} }

void QgsMapCanvas::startPreviewJobs()
{
stopPreviewJobs(); //just in case still running

QgsRectangle mapRect = mSettings.visibleExtent();

for ( int j = 0; j < 3; ++j )
{
for ( int i = 0; i < 3; ++i )
{
if ( i == 1 && j == 1 )
{
continue;
}


//copy settings, only update extent
QgsMapSettings jobSettings = mSettings;

double dx = ( i - 1 ) * mapRect.width();
double dy = ( 1 - j ) * mapRect.height();
QgsRectangle jobExtent = mapRect;
jobExtent.setXMaximum( jobExtent.xMaximum() + dx );
jobExtent.setXMinimum( jobExtent.xMinimum() + dx );
jobExtent.setYMaximum( jobExtent.yMaximum() + dy );
jobExtent.setYMinimum( jobExtent.yMinimum() + dy );

jobSettings.setExtent( jobExtent );

QgsMapRendererQImageJob *job = new QgsMapRendererParallelJob( jobSettings );
mPreviewJobs.append( job );
connect( job, SIGNAL( finished() ), this, SLOT( previewJobFinished() ) );
job->start();
}
}
}

void QgsMapCanvas::stopPreviewJobs()
{
QList< QgsMapRendererQImageJob * >::iterator it = mPreviewJobs.begin();
for ( ; it != mPreviewJobs.end(); ++it )
{
if ( *it )
{
( *it )->cancel();
}
delete ( *it );
}
mPreviewJobs.clear();
}
8 changes: 8 additions & 0 deletions src/gui/qgsmapcanvas.h
Expand Up @@ -586,6 +586,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! called when a renderer job has finished successfully or when it was canceled //! called when a renderer job has finished successfully or when it was canceled
void rendererJobFinished(); void rendererJobFinished();


//! called when a preview job has been finished
void previewJobFinished();

void mapUpdateTimeout(); void mapUpdateTimeout();


void refreshMap(); void refreshMap();
Expand Down Expand Up @@ -820,6 +823,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView


QgsSnappingUtils *mSnappingUtils = nullptr; QgsSnappingUtils *mSnappingUtils = nullptr;


QList< QgsMapRendererQImageJob * > mPreviewJobs;

//! lock the scale, so zooming can be performed using magnication //! lock the scale, so zooming can be performed using magnication
bool mScaleLocked; bool mScaleLocked;


Expand Down Expand Up @@ -868,6 +873,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView


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


void startPreviewJobs();
void stopPreviewJobs();

friend class TestQgsMapCanvas; friend class TestQgsMapCanvas;


}; // class QgsMapCanvas }; // class QgsMapCanvas
Expand Down
35 changes: 34 additions & 1 deletion src/gui/qgsmapcanvasmap.cpp
Expand Up @@ -16,7 +16,9 @@
#include "qgslogger.h" #include "qgslogger.h"
#include "qgsmapcanvas.h" #include "qgsmapcanvas.h"
#include "qgsmapcanvasmap.h" #include "qgsmapcanvasmap.h"
#include "qgsmaprendererjob.h"
#include "qgsmapsettings.h" #include "qgsmapsettings.h"
#include "qgsmaplayer.h"


#include <QPainter> #include <QPainter>


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


void QgsMapCanvasMap::setContent( const QImage &image, const QgsRectangle &rect ) void QgsMapCanvasMap::setContent( const QImage &image, const QgsRectangle &rect )
{ {
mPreviewImages.clear();

mImage = image; mImage = image;


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


void QgsMapCanvasMap::addPreviewImage( const QImage &image, const QgsRectangle &rect )
{
mPreviewImages.append( qMakePair( image, rect ) );
update();
}

QRectF QgsMapCanvasMap::boundingRect() const
{
double width = mItemSize.width();
double height = mItemSize.height();

return QRectF( -width, -height, 3 * width, 3 * height );
}

void QgsMapCanvasMap::paint( QPainter *painter ) void QgsMapCanvasMap::paint( QPainter *painter )
{ {
int w = qRound( boundingRect().width() ) - 2, h = qRound( boundingRect().height() ) - 2; // setRect() makes the size +2 :-( int w = qRound( mItemSize.width() ) - 2, h = qRound( mItemSize.height() ) - 2; // setRect() makes the size +2 :-(
if ( mImage.size() != QSize( w, h ) ) if ( mImage.size() != QSize( w, h ) )
{ {
QgsDebugMsg( QString( "map paint DIFFERENT SIZE: img %1,%2 item %3,%4" ).arg( mImage.width() ).arg( mImage.height() ).arg( w ).arg( h ) ); QgsDebugMsg( QString( "map paint DIFFERENT SIZE: img %1,%2 item %3,%4" ).arg( mImage.width() ).arg( mImage.height() ).arg( w ).arg( h ) );
// This happens on zoom events when ::paint is called before // This happens on zoom events when ::paint is called before
// the renderer has completed // the renderer has completed
} }


/*Offset between 0/0 and mRect.xMinimum/mRect.yMinimum.
We need to consider the offset, because mRect is not updated yet and there might be an offset*/
QgsPoint pt = toMapCoordinates( QPoint( 0, 0 ) );
double offsetX = pt.x() - mRect.xMinimum();
double offsetY = pt.y() - mRect.yMaximum();

//draw preview images first
QMap< QgsRectangle, QImage >::const_iterator previewIt = mPreviewImages.constBegin();
for ( ; previewIt != mPreviewImages.constEnd(); ++previewIt )
{
QPointF ul = toCanvasCoordinates( QgsPoint( previewIt.key().xMinimum() + offsetX, previewIt.key().yMaximum() + offsetY ) );
QPointF lr = toCanvasCoordinates( QgsPoint( previewIt.key().xMaximum() + offsetX, previewIt.key().yMinimum() + offsetY ) );
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() ) );
}

painter->drawImage( QRect( 0, 0, w, h ), mImage ); painter->drawImage( QRect( 0, 0, w, h ), mImage );


// For debugging: // For debugging:
Expand Down
7 changes: 7 additions & 0 deletions src/gui/qgsmapcanvasmap.h
Expand Up @@ -45,9 +45,16 @@ class QgsMapCanvasMap : public QgsMapCanvasItem


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


void addPreviewImage( const QImage &image, const QgsRectangle &rect );

QRectF boundingRect() const;

private: private:


QImage mImage; QImage mImage;

//! Preview images for panning. Usually cover area around the rendered image
QList< QPair< QImage, QgsRectangle > > mPreviewImages;
}; };


/// @endcond /// @endcond
Expand Down

0 comments on commit 2d531e5

Please sign in to comment.