Skip to content

Commit

Permalink
Add quick hasCacheImage method to QgsMapRendererCache
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Feb 1, 2017
1 parent d0e6e17 commit 0aa085d
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 1 deletion.
2 changes: 2 additions & 0 deletions python/core/qgsmaprenderercache.sip
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class QgsMapRendererCache : QObject

void setCacheImage( const QString& cacheKey, const QImage& image, const QStringList& dependentLayerIds = QStringList() );

bool hasCacheImage( const QString& cacheKey ) const;

QImage cacheImage( const QString& cacheKey ) const;

void clearCacheImage( const QString& cacheKey );
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsmaprenderercache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ void QgsMapRendererCache::setCacheImage( const QString& cacheKey, const QImage&
mCachedImages[cacheKey] = params;
}

bool QgsMapRendererCache::hasCacheImage( const QString& cacheKey ) const
{
return mCachedImages.contains( cacheKey );
}

QImage QgsMapRendererCache::cacheImage( const QString& cacheKey ) const
{
QMutexLocker lock( &mMutex );
Expand Down
8 changes: 8 additions & 0 deletions src/core/qgsmaprenderercache.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,19 @@ class CORE_EXPORT QgsMapRendererCache : public QObject
*/
void setCacheImage( const QString& cacheKey, const QImage& image, const QStringList& dependentLayerIds = QStringList() );

/**
* Returns true if the cache contains an image with the specified \a cacheKey.
* @note added in QGIS 3.0
* @see cacheImage()
*/
bool hasCacheImage( const QString& cacheKey ) const;

/**
* Returns the cached image for the specified \a cacheKey. The \a cacheKey usually
* matches the QgsMapLayer::id() which the image is a render of.
* Returns a null image if it is not cached.
* @see setCacheImage()
* @see hasCacheImage()
*/
QImage cacheImage( const QString& cacheKey ) const;

Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsmaprendererjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
job.context.setFeatureFilterProvider( mFeatureFilterProvider );

// if we can use the cache, let's do it and avoid rendering!
if ( mCache && !mCache->cacheImage( ml->id() ).isNull() )
if ( mCache && mCache->hasCacheImage( ml->id() ) )
{
job.cached = true;
job.img = new QImage( mCache->cacheImage( ml->id() ) );
Expand Down
26 changes: 26 additions & 0 deletions tests/src/python/test_qgsmaprenderercache.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,35 @@ def testSetCacheImages(self):
# not set image
im = cache.cacheImage('littlehands')
self.assertTrue(im.isNull())
self.assertFalse(cache.hasCacheImage('littlehands'))

# set image
im = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('littlehands', im)
self.assertFalse(im.isNull())
self.assertEqual(cache.cacheImage('littlehands'), im)
self.assertTrue(cache.hasCacheImage('littlehands'))

# test another not set image when cache has images
self.assertTrue(cache.cacheImage('bad').isNull())
self.assertFalse(cache.hasCacheImage('bad'))

# clear cache image
cache.clearCacheImage('not in cache') # no crash!
cache.clearCacheImage('littlehands')
im = cache.cacheImage('littlehands')
self.assertTrue(im.isNull())
self.assertFalse(cache.hasCacheImage('littlehands'))

# clear whole cache
im = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('littlehands', im)
self.assertFalse(im.isNull())
self.assertTrue(cache.hasCacheImage('littlehands'))
cache.clear()
im = cache.cacheImage('littlehands')
self.assertTrue(im.isNull())
self.assertFalse(cache.hasCacheImage('littlehands'))

def testInit(self):
cache = QgsMapRendererCache()
Expand All @@ -63,26 +69,31 @@ def testInit(self):
im = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('layer', im)
self.assertFalse(cache.cacheImage('layer').isNull())
self.assertTrue(cache.hasCacheImage('layer'))

# re init, without changing extent or scale
self.assertTrue(cache.init(extent, 1000))

# image should still be in cache
self.assertFalse(cache.cacheImage('layer').isNull())
self.assertTrue(cache.hasCacheImage('layer'))

# reinit with different scale
self.assertFalse(cache.init(extent, 2000))
# cache should be cleared
self.assertTrue(cache.cacheImage('layer').isNull())
self.assertFalse(cache.hasCacheImage('layer'))

# readd image to cache
cache.setCacheImage('layer', im)
self.assertFalse(cache.cacheImage('layer').isNull())
self.assertTrue(cache.hasCacheImage('layer'))

# change extent
self.assertFalse(cache.init(QgsRectangle(11, 12, 13, 14), 2000))
# cache should be cleared
self.assertTrue(cache.cacheImage('layer').isNull())
self.assertFalse(cache.hasCacheImage('layer'))

def testRequestRepaintSimple(self):
""" test requesting repaint with a single dependent layer """
Expand All @@ -96,11 +107,13 @@ def testRequestRepaintSimple(self):
im = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('xxx', im, [layer.id()])
self.assertFalse(cache.cacheImage('xxx').isNull())
self.assertTrue(cache.hasCacheImage('xxx'))

# trigger repaint on layer
layer.triggerRepaint()
# cache image should be cleared
self.assertTrue(cache.cacheImage('xxx').isNull())
self.assertFalse(cache.hasCacheImage('xxx'))
QgsProject.instance().removeMapLayer(layer.id())

def testRequestRepaintMultiple(self):
Expand All @@ -118,6 +131,7 @@ def testRequestRepaintMultiple(self):
im1 = QImage(200, 200, QImage.Format_RGB32)
cache.setCacheImage('nolayer', im1)
self.assertFalse(cache.cacheImage('nolayer').isNull())
self.assertTrue(cache.hasCacheImage('nolayer'))

# trigger repaint on layer
layer1.triggerRepaint()
Expand All @@ -126,6 +140,7 @@ def testRequestRepaintMultiple(self):
layer2.triggerRepaint()
# cache image should still exist - it's not dependent on layers
self.assertFalse(cache.cacheImage('nolayer').isNull())
self.assertTrue(cache.hasCacheImage('nolayer'))

# image depends on 1 layer
im_l1 = QImage(200, 200, QImage.Format_RGB32)
Expand All @@ -140,29 +155,40 @@ def testRequestRepaintMultiple(self):
cache.setCacheImage('im2', im_l2, [layer2.id()])

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

# trigger repaint layer 1 (check twice - don't want disconnect errors)
for i in range(2):
layer1.triggerRepaint()
#should be cleared
self.assertTrue(cache.cacheImage('im1').isNull())
self.assertFalse(cache.hasCacheImage('im1'))
self.assertTrue(cache.cacheImage('im1_im2').isNull())
self.assertFalse(cache.hasCacheImage('im1_im2'))
# should be retained
self.assertTrue(cache.hasCacheImage('im2'))
self.assertFalse(cache.cacheImage('im2').isNull())
self.assertEqual(cache.cacheImage('im2'), im_l2)
self.assertTrue(cache.hasCacheImage('nolayer'))
self.assertFalse(cache.cacheImage('nolayer').isNull())
self.assertEqual(cache.cacheImage('nolayer'), im1)

# trigger repaint layer 2
for i in range(2):
layer2.triggerRepaint()
#should be cleared
self.assertFalse(cache.hasCacheImage('im1'))
self.assertTrue(cache.cacheImage('im1').isNull())
self.assertFalse(cache.hasCacheImage('im1_im2'))
self.assertTrue(cache.cacheImage('im1_im2').isNull())
self.assertFalse(cache.hasCacheImage('im2'))
self.assertTrue(cache.cacheImage('im2').isNull())
# should be retained
self.assertTrue(cache.hasCacheImage('nolayer'))
self.assertFalse(cache.cacheImage('nolayer').isNull())
self.assertEqual(cache.cacheImage('nolayer'), im1)

Expand Down

0 comments on commit 0aa085d

Please sign in to comment.