Skip to content
Permalink
Browse files

Use list of map layers instead of map layer ids

  • Loading branch information
nyalldawson committed Feb 1, 2017
1 parent 0aa085d commit c84ea71bb854b609c6adebfc0fb319b83330d21c
@@ -12,7 +12,7 @@ class QgsMapRendererCache : QObject

bool init( const QgsRectangle& extent, double scale );

void setCacheImage( const QString& cacheKey, const QImage& image, const QStringList& dependentLayerIds = QStringList() );
void setCacheImage( const QString& cacheKey, const QImage& image, const QList< QgsMapLayer* >& dependentLayers = QList< QgsMapLayer* >() );

bool hasCacheImage( const QString& cacheKey ) const;

@@ -93,6 +93,11 @@ inline static QgsMapLayer* _qgis_findLayer( const QList< QgsMapLayer*> layers, c
}
}

inline uint qHash( const QPointer< QgsMapLayer >& key )
{
return qHash( key ? key->id() : QString() );
}

///@endcond

#endif // QGSMAPLAYERLISTUTILS_H
@@ -15,8 +15,8 @@

#include "qgsmaprenderercache.h"

#include "qgsproject.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerlistutils.h"

QgsMapRendererCache::QgsMapRendererCache()
{
@@ -35,44 +35,42 @@ void QgsMapRendererCache::clearInternal()
mScale = 0;

// make sure we are disconnected from all layers
Q_FOREACH ( const QString& id, mConnectedLayerIds )
Q_FOREACH ( const QPointer< QgsMapLayer >& layer, mConnectedLayers )
{
QgsMapLayer* layer = QgsProject::instance()->mapLayer( id );
if ( layer )
if ( layer.data() )
{
disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapRendererCache::layerRequestedRepaint );
disconnect( layer.data(), &QgsMapLayer::repaintRequested, this, &QgsMapRendererCache::layerRequestedRepaint );
}
}
mCachedImages.clear();
mConnectedLayerIds.clear();
mConnectedLayers.clear();
}

void QgsMapRendererCache::dropUnusedConnections()
{
QSet< QString > stillDepends = dependentLayerIds();
QSet< QString > disconnects = mConnectedLayerIds.subtract( stillDepends );
Q_FOREACH ( const QString& id, disconnects )
QSet< QPointer< QgsMapLayer > > stillDepends = dependentLayers();
QSet< QPointer< QgsMapLayer > > disconnects = mConnectedLayers.subtract( stillDepends );
Q_FOREACH ( const QPointer< QgsMapLayer >& layer, disconnects )
{
QgsMapLayer* layer = QgsProject::instance()->mapLayer( id );
if ( layer )
if ( layer.data() )
{
disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapRendererCache::layerRequestedRepaint );
disconnect( layer.data(), &QgsMapLayer::repaintRequested, this, &QgsMapRendererCache::layerRequestedRepaint );
}
}

mConnectedLayerIds = stillDepends;
mConnectedLayers = stillDepends;
}

QSet< QString > QgsMapRendererCache::dependentLayerIds() const
QSet<QPointer<QgsMapLayer> > QgsMapRendererCache::dependentLayers() const
{
QSet< QString > result;
QSet< QPointer< QgsMapLayer > > result;
QMap<QString, CacheParameters>::const_iterator it = mCachedImages.constBegin();
for ( ; it != mCachedImages.constEnd(); ++it )
{
Q_FOREACH ( const QPointer< QgsMapLayer >& l, it.value().dependentLayers )
{
if ( l.data() )
result << l->id();
result << l;
}
}
return result;
@@ -96,24 +94,23 @@ bool QgsMapRendererCache::init( const QgsRectangle& extent, double scale )
return false;
}

void QgsMapRendererCache::setCacheImage( const QString& cacheKey, const QImage& image, const QStringList& dependentLayerIds )
void QgsMapRendererCache::setCacheImage( const QString& cacheKey, const QImage& image, const QList<QgsMapLayer*>& dependentLayers )
{
QMutexLocker lock( &mMutex );

CacheParameters params;
params.cachedImage = image;

// connect to the layer to listen to layer's repaintRequested() signals
Q_FOREACH ( const QString& id, dependentLayerIds )
Q_FOREACH ( QgsMapLayer* layer, dependentLayers )
{
QgsMapLayer* layer = QgsProject::instance()->mapLayer( id );
if ( layer )
{
params.dependentLayers << layer;
if ( !mConnectedLayerIds.contains( id ) )
if ( !mConnectedLayers.contains( QPointer< QgsMapLayer >( layer ) ) )
{
connect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapRendererCache::layerRequestedRepaint );
mConnectedLayerIds << id;
mConnectedLayers << layer;
}
}
}
@@ -61,12 +61,12 @@ class CORE_EXPORT QgsMapRendererCache : public QObject
/**
* Set the cached \a image for a particular \a cacheKey. The \a cacheKey usually
* matches the QgsMapLayer::id() which the image is a render of.
* A list of \a dependentLayerIds should be passed containing all layer IDs
* A list of \a dependentLayers should be passed containing all layer
* on which this cache image is dependent. If any of these layers triggers a
* repaint then the cache image will be cleared.
* @see cacheImage()
*/
void setCacheImage( const QString& cacheKey, const QImage& image, const QStringList& dependentLayerIds = QStringList() );
void setCacheImage( const QString& cacheKey, const QImage& image, const QList< QgsMapLayer* >& dependentLayers = QList< QgsMapLayer* >() );

/**
* Returns true if the cache contains an image with the specified \a cacheKey.
@@ -108,16 +108,16 @@ class CORE_EXPORT QgsMapRendererCache : public QObject
//! Disconnects from layers we no longer care about
void dropUnusedConnections();

QSet<QString> dependentLayerIds() const;
QSet< QPointer< QgsMapLayer > > dependentLayers() const;

mutable QMutex mMutex;
QgsRectangle mExtent;
double mScale = 0;

//! Map of cache key to cache parameters
QMap<QString, CacheParameters> mCachedImages;
//! List of all layer ids on which this cache is currently connected
QSet< QString > mConnectedLayerIds;
//! List of all layers on which this cache is currently connected
QSet< QPointer< QgsMapLayer > > mConnectedLayers;
};


@@ -243,7 +243,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
{
job.opacity = 1.0 - vl->layerTransparency() / 100.0;
}
job.layerId = ml->id();
job.layer = ml;
job.renderingTime = -1;

job.context = QgsRenderContext::fromMapSettings( mSettings );
@@ -323,10 +323,10 @@ void QgsMapRendererJob::cleanupJobs( LayerRenderJobs& jobs )
delete job.context.painter();
job.context.setPainter( nullptr );

if ( mCache && !job.cached && !job.context.renderingStopped() )
if ( mCache && !job.cached && !job.context.renderingStopped() && job.layer )
{
QgsDebugMsg( "caching image for " + job.layerId );
mCache->setCacheImage( job.layerId, *job.img, QStringList() << job.layerId );
QgsDebugMsg( "caching image for " + ( job.layer ? job.layer->id() : QString() ) );
mCache->setCacheImage( job.layer->id(), *job.img, QList< QgsMapLayer* >() << job.layer );
}

delete job.img;
@@ -380,7 +380,7 @@ void QgsMapRendererJob::logRenderingTime( const LayerRenderJobs& jobs )

QMultiMap<int, QString> elapsed;
Q_FOREACH ( const LayerRenderJob& job, jobs )
elapsed.insert( job.renderingTime, job.layerId );
elapsed.insert( job.renderingTime, job.layer ? job.layer->id() : QString() );

QList<int> tt( elapsed.uniqueKeys() );
qSort( tt.begin(), tt.end(), qGreater<int>() );
@@ -50,7 +50,7 @@ struct LayerRenderJob
QPainter::CompositionMode blendMode;
double opacity;
bool cached; // if true, img already contains cached image from previous rendering
QString layerId;
QPointer< QgsMapLayer > layer;
int renderingTime; //!< Time it took to render the layer in ms (it is -1 if not rendered or still rendering)
};

@@ -21,6 +21,7 @@
#include "qgsmaplayerrenderer.h"
#include "qgspallabeling.h"
#include "qgsproject.h"
#include "qgsmaplayer.h"

#include <QtConcurrentMap>

@@ -220,7 +221,7 @@ void QgsMapRendererParallelJob::renderLayerStatic( LayerRenderJob& job )

QTime t;
t.start();
QgsDebugMsgLevel( QString( "job %1 start (layer %2)" ).arg( reinterpret_cast< quint64 >( &job ), 0, 16 ).arg( job.layerId ), 2 );
QgsDebugMsgLevel( QString( "job %1 start (layer %2)" ).arg( reinterpret_cast< quint64 >( &job ), 0, 16 ).arg( job.layer ? job.layer->id() : QString() ), 2 );

try
{
@@ -242,7 +243,7 @@ void QgsMapRendererParallelJob::renderLayerStatic( LayerRenderJob& job )
}

job.renderingTime = t.elapsed();
QgsDebugMsgLevel( QString( "job %1 end [%2 ms] (layer %3)" ).arg( reinterpret_cast< quint64 >( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layerId ), 2 );
QgsDebugMsgLevel( QString( "job %1 end [%2 ms] (layer %3)" ).arg( reinterpret_cast< quint64 >( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layer ? job.layer->id() : QString() ), 2 );
}


@@ -105,7 +105,7 @@ def testRequestRepaintSimple(self):
# add image to cache
cache = QgsMapRendererCache()
im = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('xxx', im, [layer.id()])
cache.setCacheImage('xxx', im, [layer])
self.assertFalse(cache.cacheImage('xxx').isNull())
self.assertTrue(cache.hasCacheImage('xxx'))

@@ -144,15 +144,15 @@ def testRequestRepaintMultiple(self):

# image depends on 1 layer
im_l1 = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('im1', im_l1, [layer1.id()])
cache.setCacheImage('im1', im_l1, [layer1])

# image depends on 2 layers
im_l1_l2 = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('im1_im2', im_l1_l2, [layer1.id(), layer2.id()])
cache.setCacheImage('im1_im2', im_l1_l2, [layer1, layer2])

# image depends on 2nd layer alone
im_l2 = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('im2', im_l2, [layer2.id()])
cache.setCacheImage('im2', im_l2, [layer2])

self.assertFalse(cache.cacheImage('im1').isNull())
self.assertTrue(cache.hasCacheImage('im1'))

0 comments on commit c84ea71

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