qgis_rendercachepatch_v5_22Oct2009.diff

Updated to use QImage - Tim Sutton, 2009-10-22 02:41 PM

Download (16 KB)

View differences:

src/app/qgsoptions.cpp (working copy)
149 149

  
150 150
  //set the state of the checkboxes
151 151
  chkAntiAliasing->setChecked( settings.value( "/qgis/enable_anti_aliasing", false ).toBool() );
152
  chkUseRenderCaching->setChecked( settings.value( "/qgis/enable_render_caching", false ).toBool() );
152 153

  
153 154
  // Slightly awkard here at the settings value is true to use QImage,
154 155
  // but the checkbox is true to use QPixmap
......
365 366
  settings.setValue( "/qgis/addPostgisDC", cbxAddPostgisDC->isChecked() );
366 367
  settings.setValue( "/qgis/new_layers_visible", chkAddedVisibility->isChecked() );
367 368
  settings.setValue( "/qgis/enable_anti_aliasing", chkAntiAliasing->isChecked() );
369
  settings.setValue( "/qgis/enable_render_caching", chkUseRenderCaching->isChecked() );
368 370
  settings.setValue( "/qgis/use_qimage_to_render", !( chkUseQPixmap->isChecked() ) );
369 371
  settings.setValue( "qgis/capitaliseLayerName", capitaliseCheckBox->isChecked() );
370 372
  settings.setValue( "qgis/askToSaveProjectChanges", chbAskToSaveProjectChanges->isChecked() );
......
530 532
  // used (we we can. but it then doesn't do anti-aliasing, and this
531 533
  // will confuse people).
532 534
  if ( chkAntiAliasing->isChecked() )
535
  {
533 536
    chkUseQPixmap->setChecked( false );
537
  }
534 538

  
535 539
}
536 540

  
......
540 544
  // used (we we can. but it then doesn't do anti-aliasing, and this
541 545
  // will confuse people).
542 546
  if ( chkUseQPixmap->isChecked() )
547
  {
543 548
    chkAntiAliasing->setChecked( false );
549
  }
544 550

  
545 551
}
546 552

  
src/app/qgsvectorlayerproperties.cpp (working copy)
658 658
  // update symbology
659 659
  emit refreshLegend( layer->getLayerID(), false );
660 660

  
661
  if ( layer->cacheImage() )
662
  {
663
    //no need to delete the old one, maplayer will do it if needed
664
    layer->setCacheImage( 0 );
665
  }
661 666
  layer->triggerRepaint();
662 667
  // notify the project we've made a change
663 668
  QgsProject::instance()->dirty( true );
src/core/qgsmaprenderer.h (working copy)
199 199

  
200 200
    //! current extent to be drawn
201 201
    QgsRectangle mExtent;
202
    //
203
    /** Last extent to we drew so we know if we can 
204
        used layer render caching or not. Note there are no
205
        accessors for this as it is intended to internal
206
        use only.
207
        @note added in QGIS 1.4 */
208
    QgsRectangle mLastExtent;
202 209

  
203 210
    //! indicates whether it's map image for overview
204 211
    bool mOverview;
src/core/qgsmaplayer.cpp (working copy)
75 75
  mMinScale = 0;
76 76
  mMaxScale = 100000000;
77 77
  mScaleBasedVisibility = false;
78
  mpCacheImage = 0;
78 79
}
79 80

  
80 81

  
......
82 83
QgsMapLayer::~QgsMapLayer()
83 84
{
84 85
  delete mCRS;
86
  if ( mpCacheImage ) 
87
  { 
88
    delete mpCacheImage; 
89
  }  
85 90
}
86 91

  
87 92
QgsMapLayer::LayerType QgsMapLayer::type() const
......
729 734
{
730 735
  return &mUndoStack;
731 736
}
737

  
738
void QgsMapLayer::setCacheImage( QImage * thepImage ) 
739
{ 
740
  QgsDebugMsg( "cache Image set!" );
741
  if ( mpCacheImage ) 
742
  { 
743
    delete mpCacheImage; 
744
  }  
745
  mpCacheImage = thepImage; 
746
}
src/core/qgsmaprenderer.cpp (working copy)
80 80

  
81 81
bool QgsMapRenderer::setExtent( const QgsRectangle& extent )
82 82
{
83
  //remember the previous extent
84
  mLastExtent = mExtent;
83 85

  
84 86
  // Don't allow zooms where the current extent is so small that it
85 87
  // can't be accurately represented using a double (which is what
......
207 209

  
208 210
void QgsMapRenderer::render( QPainter* painter )
209 211
{
212
  //flag to see if the render context has changed 
213
  //since the last time we rendered. If it hasnt changed we can
214
  //take some shortcuts with rendering
215
  bool mySameAsLastFlag = true;
216

  
210 217
  QgsDebugMsg( "========== Rendering ==========" );
211 218

  
212 219
  if ( mExtent.isEmpty() )
......
216 223
  }
217 224

  
218 225
  if ( mDrawing )
226
  {
219 227
    return;
228
  }
220 229

  
221 230
  QPaintDevice* thePaintDevice = painter->device();
222 231
  if ( !thePaintDevice )
......
251 260
    scaleFactor = sceneDpi / 25.4;
252 261
  }
253 262
  double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi;
254
  mRenderContext.setScaleFactor( scaleFactor );
255
  mRenderContext.setRasterScaleFactor( rasterScaleFactor );
256
  mRenderContext.setRendererScale( mScale );
263
  if ( mRenderContext.rasterScaleFactor() != rasterScaleFactor )
264
  {
265
    mRenderContext.setRasterScaleFactor( rasterScaleFactor );
266
    mySameAsLastFlag = false;
267
  }
268
  if ( mRenderContext.scaleFactor() != scaleFactor )
269
  {
270
    mRenderContext.setScaleFactor( scaleFactor );
271
    mySameAsLastFlag = false;
272
  }
273
  if ( mRenderContext.rendererScale() != mScale )
274
  {
275
    //add map scale to render context
276
    mRenderContext.setRendererScale( mScale );
277
    mySameAsLastFlag = false;
278
  }
279
  if ( mLastExtent != mExtent )
280
  {
281
    mLastExtent = mExtent;
282
    mySameAsLastFlag = false;
283
  }
257 284

  
258 285
  bool placeOverlays = false;
259 286
  QgsOverlayObjectPositionManager* overlayManager = overlayManagerFromSettings();
......
263 290
    placeOverlays = true;
264 291
  }
265 292

  
266
  //add map scale to render context
267
  mRenderContext.setRendererScale( mScale );
268

  
269 293
  // render all layers in the stack, starting at the base
270 294
  QListIterator<QString> li( mLayerSet );
271 295
  li.toBack();
......
279 303
      break;
280 304
    }
281 305

  
306
    // Store the painter in case we need to swap it out for the 
307
    // cache painter
308
    QPainter * mypContextPainter = mRenderContext.painter();
309

  
282 310
    QString layerId = li.previous();
283 311

  
284 312
    QgsDebugMsg( "Rendering at layer item " + layerId );
......
343 371
      }
344 372

  
345 373

  
346
      if ( scaleRaster )
347
      {
348
        bk_mapToPixel = mRenderContext.mapToPixel();
349
        rasterMapToPixel = mRenderContext.mapToPixel();
350
        rasterMapToPixel.setMapUnitsPerPixel( mRenderContext.mapToPixel().mapUnitsPerPixel() / rasterScaleFactor );
351
        rasterMapToPixel.setYMaximum( mSize.height() * rasterScaleFactor );
352
        mRenderContext.setMapToPixel( rasterMapToPixel );
353
        mRenderContext.painter()->save();
354
        mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
355
      }
356

  
357 374
      //create overlay objects for features within the view extent
358 375
      if ( ml->type() == QgsMapLayer::VectorLayer && overlayManager )
359 376
      {
......
376 393
          overlayManager->addLayer( vl, thisLayerOverlayList );
377 394
        }
378 395
      }
396
      QSettings mySettings;
397
      if ( ! split )//render caching does not yet cater for split extents
398
      {
399
        if ( mySettings.value ( "/qgis/enable_render_caching", false ).toBool() )
400
        {
401
          if ( !mySameAsLastFlag || ml->cacheImage() == 0 ) 
402
          {
403
            QgsDebugMsg( "\n\n\nCaching enabled but layer redraw forced by extent change or empty cache\n\n\n" );
404
            QImage * mypImage = new QImage( mRenderContext.painter()->device()->width(), 
405
                mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 ); 
406
            mypImage->fill( 0 );
407
            ml->setCacheImage( mypImage ); //no need to delete the oldone, maplayer does it for you
408
            QPainter * mypPainter = new QPainter( ml->cacheImage() );
409
            if ( mySettings.value( "/qgis/enable_anti_aliasing", false ).toBool() )
410
            {
411
              mypPainter->setRenderHint( QPainter::Antialiasing );
412
            }
413
            mRenderContext.setPainter( mypPainter  );
414
          }
415
          else if ( mySameAsLastFlag )
416
          {
417
            //draw from cached image
418
            QgsDebugMsg( "\n\n\nCaching enabled --- drawing layer from cached image\n\n\n" );
419
            mypContextPainter->drawImage( 0,0, *(ml->cacheImage()) );
420
            disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
421
            //short circuit as there is nothing else to do...
422
            continue;
423
          }
424
        }
425
      }
379 426

  
427
      if ( scaleRaster )
428
      {
429
        bk_mapToPixel = mRenderContext.mapToPixel();
430
        rasterMapToPixel = mRenderContext.mapToPixel();
431
        rasterMapToPixel.setMapUnitsPerPixel( mRenderContext.mapToPixel().mapUnitsPerPixel() / rasterScaleFactor );
432
        rasterMapToPixel.setYMaximum( mSize.height() * rasterScaleFactor );
433
        mRenderContext.setMapToPixel( rasterMapToPixel );
434
        mRenderContext.painter()->save();
435
        mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
436
      }
437

  
438

  
380 439
      if ( !ml->draw( mRenderContext ) )
381 440
      {
382 441
        emit drawError( ml );
383 442
      }
384

  
443
      else
444
      {
445
            QgsDebugMsg( "\n\n\nLayer rendered without issues\n\n\n" );
446
      }
385 447
      if ( split )
386 448
      {
387 449
        mRenderContext.setExtent( r2 );
......
397 459
        mRenderContext.painter()->restore();
398 460
      }
399 461

  
462
      if ( mySettings.value ( "/qgis/enable_render_caching", false ).toBool() )
463
      {
464
        if ( !split )
465
        {
466
          // composite the cached image into our view and then clean up from caching
467
          // by reinstating the painter as it was swapped out for caching renders
468
          delete mRenderContext.painter();
469
          mRenderContext.setPainter( mypContextPainter  );
470
          //draw from cached image that we created further up
471
          mypContextPainter->drawImage( 0,0, *(ml->cacheImage()) );
472
        }
473
      }
400 474
      disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
401 475
    }
402
    else
476
    else // layer not visible due to scale
403 477
    {
478
      //clear the cache pixmap if we changed resolution / extent
479
      QSettings mySettings;
480
      if ( mySettings.value ( "/qgis/enable_render_caching", false ).toBool() )
481
      {
482
        if ( !mySameAsLastFlag )
483
        {
484
          ml->setCacheImage( 0 ); //no need to delete the oldone, maplayer does it for you
485
        }
486
      }
404 487
      QgsDebugMsg( "Layer not rendered because it is not within the defined "
405
                   "visibility scale range" );
488
          "visibility scale range" );
406 489
    }
407 490

  
408 491
  } // while (li.hasPrevious())
src/core/qgsmaplayer.h (working copy)
24 24

  
25 25
#include <QObject>
26 26
#include <QUndoStack>
27
#include <QImage>
27 28

  
28 29
#include "qgsrectangle.h"
29 30

  
......
263 264
    /** Return pointer to layer's undo stack */
264 265
    QUndoStack* undoStack();
265 266

  
267
    /** Get the QImage used for caching render operations
268
     * @note This method was added in QGIS 1.4 **/
269
    QImage * cacheImage() { return mpCacheImage; }
270
    /** Set the QImage used for caching render operations 
271
     * @note This method was added in QGIS 1.4 **/
272
    void setCacheImage( QImage * thepImage ); 
273

  
266 274
  public slots:
267 275

  
268 276
    /** Event handler for when a coordinate transform fails due to bad vertex error */
......
360 368
    /** A flag that tells us whether to use the above vars to restrict layer visibility */
361 369
    bool mScaleBasedVisibility;
362 370

  
371
    /** Collection of undoable operations for this layer. **/
363 372
    QUndoStack mUndoStack;
364 373

  
374
    /**QImage for caching of rendering operations
375
     * @note This property was added in QGIS 1.4 **/
376
    QImage * mpCacheImage;
377

  
365 378
};
366 379

  
367 380
#endif
src/ui/qgsoptionsbase.ui (working copy)
13 13
   <string>Options</string>
14 14
  </property>
15 15
  <property name="windowIcon" >
16
   <iconset>
17
    <normaloff/>
18
   </iconset>
16
   <iconset/>
19 17
  </property>
20 18
  <property name="sizeGripEnabled" >
21 19
   <bool>true</bool>
......
195 193
           </widget>
196 194
          </item>
197 195
          <item row="1" column="0" colspan="2" >
198
           <spacer name="verticalSpacer">
199
            <property name="orientation">
196
           <spacer>
197
            <property name="orientation" >
200 198
             <enum>Qt::Vertical</enum>
201 199
            </property>
202
            <property name="sizeType">
200
            <property name="sizeType" >
203 201
             <enum>QSizePolicy::Fixed</enum>
204 202
            </property>
205
            <property name="sizeHint" stdset="0">
203
            <property name="sizeHint" >
206 204
             <size>
207 205
              <width>20</width>
208 206
              <height>10</height>
209 207
             </size>
210 208
            </property>
211 209
           </spacer>
212
          </item>          
210
          </item>
213 211
          <item row="2" column="0" colspan="2" >
214 212
           <widget class="QCheckBox" name="capitaliseCheckBox" >
215 213
            <property name="text" >
......
321 319
            </property>
322 320
           </widget>
323 321
          </item>
322
          <item row="3" column="0" colspan="2" >
323
           <widget class="QCheckBox" name="chkUseRenderCaching" >
324
            <property name="text" >
325
             <string>Use render caching where possible to speed up redraws</string>
326
            </property>
327
           </widget>
328
          </item>
324 329
         </layout>
325 330
        </widget>
326 331
       </item>
......
369 374
         </property>
370 375
         <property name="sizeHint" >
371 376
          <size>
372
           <width>20</width>
373
           <height>40</height>
377
           <width>614</width>
378
           <height>111</height>
374 379
          </size>
375 380
         </property>
376 381
        </spacer>
......
1308 1313
  </customwidget>
1309 1314
 </customwidgets>
1310 1315
 <tabstops>
1316
  <tabstop>tabWidget</tabstop>
1311 1317
  <tabstop>chbAskToSaveProjectChanges</tabstop>
1312 1318
  <tabstop>chbWarnOldProjectVersion</tabstop>
1313 1319
  <tabstop>pbnSelectionColour</tabstop>
1314 1320
  <tabstop>pbnCanvasColor</tabstop>
1315 1321
  <tabstop>cmbTheme</tabstop>
1316 1322
  <tabstop>capitaliseCheckBox</tabstop>
1323
  <tabstop>cbxLegendClassifiers</tabstop>
1317 1324
  <tabstop>cbxHideSplash</tabstop>
1325
  <tabstop>cbxIdentifyResultsDocked</tabstop>
1326
  <tabstop>cbxAttributeTableDocked</tabstop>
1327
  <tabstop>cbxAddPostgisDC</tabstop>
1318 1328
  <tabstop>chkAddedVisibility</tabstop>
1319 1329
  <tabstop>spinBoxUpdateThreshold</tabstop>
1330
  <tabstop>chkUseRenderCaching</tabstop>
1320 1331
  <tabstop>chkAntiAliasing</tabstop>
1321 1332
  <tabstop>chkUseQPixmap</tabstop>
1333
  <tabstop>cmbIdentifyMode</tabstop>
1322 1334
  <tabstop>spinBoxIdentifyValue</tabstop>
1323 1335
  <tabstop>cmbEllipsoid</tabstop>
1324 1336
  <tabstop>pbnMeasureColour</tabstop>
1337
  <tabstop>radMeters</tabstop>
1338
  <tabstop>radFeet</tabstop>
1325 1339
  <tabstop>cmbWheelAction</tabstop>
1326 1340
  <tabstop>spinZoomFactor</tabstop>
1341
  <tabstop>mOverlayAlgorithmComboBox</tabstop>
1327 1342
  <tabstop>mLineWidthSpinBox</tabstop>
1328 1343
  <tabstop>mLineColourToolButton</tabstop>
1329 1344
  <tabstop>mDefaultSnapModeComboBox</tabstop>
1330 1345
  <tabstop>mDefaultSnappingToleranceSpinBox</tabstop>
1331 1346
  <tabstop>mSearchRadiusVertexEditSpinBox</tabstop>
1347
  <tabstop>mDefaultSnappingToleranceComboBox</tabstop>
1348
  <tabstop>mSearchRadiusVertexEditComboBox</tabstop>
1349
  <tabstop>mMarkersOnlyForSelectedCheckBox</tabstop>
1332 1350
  <tabstop>mMarkerStyleComboBox</tabstop>
1351
  <tabstop>mMarkerSizeSpinBox</tabstop>
1352
  <tabstop>chkDisableAttributeValuesDlg</tabstop>
1333 1353
  <tabstop>radPromptForProjection</tabstop>
1334 1354
  <tabstop>radUseProjectProjection</tabstop>
1335 1355
  <tabstop>radUseGlobalProjection</tabstop>
......
1337 1357
  <tabstop>pbnSelectProjection</tabstop>
1338 1358
  <tabstop>grpLocale</tabstop>
1339 1359
  <tabstop>cboLocale</tabstop>
1360
  <tabstop>grpProxy</tabstop>
1361
  <tabstop>leProxyHost</tabstop>
1362
  <tabstop>leProxyPort</tabstop>
1363
  <tabstop>leProxyUser</tabstop>
1364
  <tabstop>leProxyPassword</tabstop>
1365
  <tabstop>mProxyTypeComboBox</tabstop>
1366
  <tabstop>mAddUrlPushButton</tabstop>
1367
  <tabstop>mRemoveUrlPushButton</tabstop>
1368
  <tabstop>mExcludeUrlListWidget</tabstop>
1340 1369
  <tabstop>buttonBox</tabstop>
1341
  <tabstop>tabWidget</tabstop>
1342 1370
 </tabstops>
1343 1371
 <resources/>
1344 1372
 <connections/>