Skip to content
Permalink
Browse files

Merge pull request #4777 from nyalldawson/preview

Forward port Sourcepole's work on map panning previews
  • Loading branch information
nyalldawson committed Jul 18, 2017
2 parents 857f843 + 1e145b3 commit 72e35135db7ada23e2a6441f725d06e9d4f376a8
Showing with 115 additions and 1 deletion.
  1. +66 −0 src/gui/qgsmapcanvas.cpp
  2. +8 −0 src/gui/qgsmapcanvas.h
  3. +34 −1 src/gui/qgsmapcanvasmap.cpp
  4. +7 −0 src/gui/qgsmapcanvasmap.h
@@ -507,6 +507,7 @@ void QgsMapCanvas::refreshMap()
QgsDebugMsgLevel( "CANVAS refresh!", 3 );

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

//build the expression context
QgsExpressionContext expressionContext;
@@ -628,6 +629,7 @@ void QgsMapCanvas::rendererJobFinished()
p.end();

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

// now we are in a slot called from mJob - do not delete it immediately
@@ -638,6 +640,17 @@ void QgsMapCanvas::rendererJobFinished()
emit mapCanvasRefreshed();
}

void QgsMapCanvas::previewJobFinished()
{
QgsMapRendererQImageJob *job = qobject_cast<QgsMapRendererQImageJob *>( sender() );
Q_ASSERT( job );

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

QgsRectangle QgsMapCanvas::imageRect( const QImage &img, const QgsMapSettings &mapSettings )
{
// This is a hack to pass QgsMapCanvasItem::setRect what it
@@ -2113,3 +2126,56 @@ const QgsLabelingEngineSettings &QgsMapCanvas::labelingEngineSettings() const
{
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 );
jobSettings.setFlag( QgsMapSettings::DrawLabeling, false );

QgsMapRendererQImageJob *job = new QgsMapRendererParallelJob( jobSettings );
mPreviewJobs.append( job );
connect( job, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
job->start();
}
}
}

void QgsMapCanvas::stopPreviewJobs()
{
QList< QgsMapRendererQImageJob * >::const_iterator it = mPreviewJobs.constBegin();
for ( ; it != mPreviewJobs.constEnd(); ++it )
{
if ( *it )
{
disconnect( *it, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
connect( *it, &QgsMapRendererQImageJob::finished, *it, &QgsMapRendererQImageJob::deleteLater );
( *it )->cancelWithoutBlocking();
}
}
mPreviewJobs.clear();
}
@@ -586,6 +586,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! called when a renderer job has finished successfully or when it was canceled
void rendererJobFinished();

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

void mapUpdateTimeout();

void refreshMap();
@@ -822,6 +825,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView

QgsSnappingUtils *mSnappingUtils = nullptr;

QList< QgsMapRendererQImageJob * > mPreviewJobs;

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

@@ -870,6 +875,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView

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

void startPreviewJobs();
void stopPreviewJobs();

friend class TestQgsMapCanvas;

}; // class QgsMapCanvas
@@ -16,7 +16,9 @@
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmapcanvasmap.h"
#include "qgsmaprendererjob.h"
#include "qgsmapsettings.h"
#include "qgsmaplayer.h"

#include <QPainter>

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

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

mImage = image;

// 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
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 )
{
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 ) )
{
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
// 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*/
QgsPointXY pt = toMapCoordinates( QPoint( 0, 0 ) );
double offsetX = pt.x() - mRect.xMinimum();
double offsetY = pt.y() - mRect.yMaximum();

//draw preview images first
QList< QPair< QImage, QgsRectangle > >::const_iterator imIt = mPreviewImages.constBegin();
for ( ; imIt != mPreviewImages.constEnd(); ++imIt )
{
QPointF ul = toCanvasCoordinates( QgsPoint( imIt->second.xMinimum() + offsetX, imIt->second.yMaximum() + offsetY ) );
QPointF lr = toCanvasCoordinates( QgsPoint( imIt->second.xMaximum() + offsetX, imIt->second.yMinimum() + offsetY ) );
painter->drawImage( QRectF( ul.x(), ul.y(), lr.x() - ul.x(), lr.y() - ul.y() ), imIt->first, QRect( 0, 0, imIt->first.width(), imIt->first.height() ) );
}

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

// For debugging:
@@ -45,9 +45,16 @@ class QgsMapCanvasMap : public QgsMapCanvasItem

virtual void paint( QPainter *painter ) override;

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

QRectF boundingRect() const override;

private:

QImage mImage;

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

/// @endcond

0 comments on commit 72e3513

Please sign in to comment.
You can’t perform that action at this time.