qwt_plot_rasteritem.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_plot_rasteritem.h"
00011 #include "qwt_scale_map.h"
00012 #include "qwt_painter.h"
00013 #include <qapplication.h>
00014 #include <qdesktopwidget.h>
00015 #include <qpainter.h>
00016 #include <qpaintengine.h>
00017 #include <qmath.h>
00018 #include <qthread.h>
00019 #include <qfuture.h>
00020 #include <qtconcurrentrun.h>
00021 #include <float.h>
00022 
00023 class QwtPlotRasterItem::PrivateData
00024 {
00025 public:
00026     PrivateData():
00027         alpha( -1 ),
00028         paintAttributes( QwtPlotRasterItem::PaintInDeviceResolution )
00029     {
00030         cache.policy = QwtPlotRasterItem::NoCache;
00031     }
00032 
00033     int alpha;
00034 
00035     QwtPlotRasterItem::PaintAttributes paintAttributes;
00036 
00037     struct ImageCache
00038     {
00039         QwtPlotRasterItem::CachePolicy policy;
00040         QRectF area;
00041         QSizeF size;
00042         QImage image;
00043     } cache;
00044 };
00045 
00046 
00047 static QRectF qwtAlignRect(const QRectF &rect)
00048 {
00049     QRectF r;
00050     r.setLeft( qRound( rect.left() ) );
00051     r.setRight( qRound( rect.right() ) );
00052     r.setTop( qRound( rect.top() ) );
00053     r.setBottom( qRound( rect.bottom() ) );
00054 
00055     return r;
00056 }
00057 
00058 static QRectF qwtStripRect(const QRectF &rect, const QRectF &area,
00059     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00060     const QwtInterval &xInterval, const QwtInterval &yInterval)
00061 {
00062     QRectF r = rect;
00063     if ( xInterval.borderFlags() & QwtInterval::ExcludeMinimum )
00064     {
00065         if ( area.left() <= xInterval.minValue() )
00066         {
00067             if ( xMap.isInverting() )
00068                 r.adjust(0, 0, -1, 0);
00069             else
00070                 r.adjust(1, 0, 0, 0);
00071         }
00072     }
00073 
00074     if ( xInterval.borderFlags() & QwtInterval::ExcludeMaximum )
00075     {
00076         if ( area.right() >= xInterval.maxValue() )
00077         {
00078             if ( xMap.isInverting() )
00079                 r.adjust(1, 0, 0, 0);
00080             else
00081                 r.adjust(0, 0, -1, 0);
00082         }
00083     }
00084 
00085     if ( yInterval.borderFlags() & QwtInterval::ExcludeMinimum )
00086     {
00087         if ( area.top() <= yInterval.minValue() )
00088         {
00089             if ( yMap.isInverting() )
00090                 r.adjust(0, 0, 0, -1);
00091             else
00092                 r.adjust(0, 1, 0, 0);
00093         }
00094     }
00095 
00096     if ( yInterval.borderFlags() & QwtInterval::ExcludeMaximum )
00097     {
00098         if ( area.bottom() >= yInterval.maxValue() )
00099         {
00100             if ( yMap.isInverting() )
00101                 r.adjust(0, 1, 0, 0);
00102             else
00103                 r.adjust(0, 0, 0, -1);
00104         }
00105     }
00106 
00107     return r;
00108 }
00109 
00110 static QImage qwtExpandImage(const QImage &image,
00111     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00112     const QRectF &area, const QRectF &area2, const QRectF &paintRect,
00113     const QwtInterval &xInterval, const QwtInterval &yInterval )
00114 {
00115     const QRectF strippedRect = qwtStripRect(paintRect, area2,
00116         xMap, yMap, xInterval, yInterval);
00117     const QSize sz = strippedRect.toRect().size();
00118 
00119     const int w = image.width();
00120     const int h = image.height();
00121 
00122     const QRectF r = QwtScaleMap::transform(xMap, yMap, area).normalized();
00123     const double pw = ( r.width() - 1) / w;
00124     const double ph = ( r.height() - 1) / h;
00125 
00126     double px0, py0;
00127     if ( !xMap.isInverting() )
00128     {
00129         px0 = xMap.transform( area2.left() );
00130         px0 = qRound( px0 );
00131         px0 = px0 - xMap.transform( area.left() );
00132     }
00133     else
00134     {
00135         px0 = xMap.transform( area2.right() );
00136         px0 = qRound( px0 );
00137         px0 -= xMap.transform( area.right() );
00138 
00139         px0 -= 1.0;
00140     }
00141     px0 += strippedRect.left() - paintRect.left();
00142 
00143     if ( !yMap.isInverting() )
00144     {
00145         py0 = yMap.transform( area2.top() );
00146         py0 = qRound( py0 );
00147         py0 -= yMap.transform( area.top() );
00148     }
00149     else
00150     {
00151         py0 = yMap.transform( area2.bottom() );
00152         py0 = qRound( py0 );
00153         py0 -= yMap.transform( area.bottom() );
00154 
00155         py0 -= 1.0;
00156     }
00157     py0 += strippedRect.top() - paintRect.top();
00158 
00159     QImage expanded(sz, image.format());
00160 
00161     switch( image.depth() )
00162     {
00163         case 32:
00164         {
00165             for ( int y1 = 0; y1 < h; y1++ )
00166             {
00167                 int yy1;
00168                 if ( y1 == 0 )
00169                 {
00170                     yy1 = 0;
00171                 }
00172                 else
00173                 {
00174                     yy1 = qRound( y1 * ph - py0 );
00175                     if ( yy1 < 0 )
00176                         yy1 = 0;
00177                 }
00178 
00179                 int yy2;
00180                 if ( y1 == h - 1 )
00181                 {
00182                     yy2 = sz.height();
00183                 }
00184                 else
00185                 {
00186                     yy2 = qRound( ( y1 + 1 ) * ph - py0 );
00187                     if ( yy2 > sz.height() )
00188                         yy2 = sz.height();
00189                 }
00190 
00191                 const quint32 *line1 = 
00192                     reinterpret_cast<const quint32 *>( image.scanLine( y1 ) );
00193 
00194                 for ( int x1 = 0; x1 < w; x1++ )
00195                 {
00196                     int xx1;
00197                     if ( x1 == 0 )
00198                     {
00199                         xx1 = 0;
00200                     }
00201                     else
00202                     {
00203                         xx1 = qRound( x1 * pw - px0 );
00204                         if ( xx1 < 0 )
00205                             xx1 = 0;
00206                     }
00207 
00208                     int xx2;
00209                     if ( x1 == w - 1 )
00210                     {
00211                         xx2 = sz.width();
00212                     }
00213                     else
00214                     {
00215                         xx2 = qRound( ( x1 + 1 ) * pw - px0 );
00216                         if ( xx2 > sz.width() )
00217                             xx2 = sz.width();
00218                     }
00219 
00220                     const quint32 rgb( line1[x1] );
00221                     for ( int y2 = yy1; y2 < yy2; y2++ )
00222                     {
00223                         quint32 *line2 = reinterpret_cast<quint32 *>( 
00224                             expanded.scanLine( y2 ) );
00225 
00226                         for ( int x2 = xx1; x2 < xx2; x2++ ) 
00227                             line2[x2] = rgb;
00228                     }       
00229                 }   
00230             }   
00231             break;
00232         }
00233         case 8:
00234         {
00235             for ( int y1 = 0; y1 < h; y1++ )
00236             {
00237                 int yy1;
00238                 if ( y1 == 0 )
00239                 {
00240                     yy1 = 0;
00241                 }   
00242                 else
00243                 {
00244                     yy1 = qRound( y1 * ph - py0 );
00245                     if ( yy1 < 0 )
00246                         yy1 = 0; 
00247                 }       
00248                 
00249                 int yy2;
00250                 if ( y1 == h - 1 )
00251                 {
00252                     yy2 = sz.height();
00253                 }   
00254                 else
00255                 {
00256                     yy2 = qRound( ( y1 + 1 ) * ph - py0 );
00257                     if ( yy2 > sz.height() )
00258                         yy2 = sz.height();
00259                 }
00260     
00261                 const uchar *line1 = image.scanLine( y1 );
00262 
00263                 for ( int x1 = 0; x1 < w; x1++ )
00264                 {
00265                     int xx1;
00266                     if ( x1 == 0 )
00267                     {
00268                         xx1 = 0;
00269                     }
00270                     else
00271                     {
00272                         xx1 = qRound( x1 * pw - px0 );
00273                         if ( xx1 < 0 )
00274                             xx1 = 0;
00275                     }
00276 
00277                     int xx2;
00278                     if ( x1 == w - 1 )
00279                     {
00280                         xx2 = sz.width();
00281                     }
00282                     else
00283                     {
00284                         xx2 = qRound( ( x1 + 1 ) * pw - px0 );
00285                         if ( xx2 > sz.width() )
00286                             xx2 = sz.width();
00287                     }
00288 
00289                     for ( int y2 = yy1; y2 < yy2; y2++ )
00290                     {
00291                         uchar *line2 = expanded.scanLine( y2 );
00292                         memset( line2 + xx1, line1[x1], xx2 - xx1 );
00293                     }       
00294                 }   
00295             }
00296             break;
00297         }
00298         default:
00299             expanded = image;
00300     }
00301     
00302     return expanded;
00303 }   
00304 
00305 static QRectF qwtExpandToPixels(const QRectF &rect, const QRectF &pixelRect)
00306 {
00307     const double pw = pixelRect.width();
00308     const double ph = pixelRect.height();
00309 
00310     const double dx1 = pixelRect.left() - rect.left();
00311     const double dx2 = pixelRect.right() - rect.right();
00312     const double dy1 = pixelRect.top() - rect.top();
00313     const double dy2 = pixelRect.bottom() - rect.bottom();
00314 
00315     QRectF r;
00316     r.setLeft( pixelRect.left() - qCeil( dx1 / pw ) * pw );
00317     r.setTop( pixelRect.top() - qCeil( dy1 / ph ) * ph );
00318     r.setRight( pixelRect.right() - qFloor( dx2 / pw ) * pw );
00319     r.setBottom( pixelRect.bottom() - qFloor( dy2 / ph ) * ph );
00320 
00321     return r;
00322 }
00323 
00324 static void qwtTransformMaps( const QTransform &tr,
00325     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00326     QwtScaleMap &xxMap, QwtScaleMap &yyMap )
00327 {
00328     const QPointF p1 = tr.map( QPointF( xMap.p1(), yMap.p1() ) );
00329     const QPointF p2 = tr.map( QPointF( xMap.p2(), yMap.p2() ) );
00330 
00331     xxMap = xMap;
00332     xxMap.setPaintInterval( p1.x(), p2.x() );
00333 
00334     yyMap = yMap;
00335     yyMap.setPaintInterval( p1.y(), p2.y() );
00336 }
00337 
00338 static void qwtAdjustMaps( QwtScaleMap &xMap, QwtScaleMap &yMap,
00339     const QRectF &area, const QRectF &paintRect)
00340 {
00341     double sx1 = area.left();
00342     double sx2 = area.right();
00343     if ( xMap.isInverting() )
00344         qSwap(sx1, sx2);
00345 
00346     double sy1 = area.top();
00347     double sy2 = area.bottom();
00348 
00349     if ( yMap.isInverting() )
00350         qSwap(sy1, sy2);
00351 
00352     xMap.setPaintInterval(paintRect.left(), paintRect.right());
00353     xMap.setScaleInterval(sx1, sx2);
00354 
00355     yMap.setPaintInterval(paintRect.top(), paintRect.bottom());
00356     yMap.setScaleInterval(sy1, sy2);
00357 }
00358 
00359 static bool qwtUseCache( QwtPlotRasterItem::CachePolicy policy,
00360     const QPainter *painter )
00361 {
00362     bool doCache = false;
00363 
00364     if ( policy == QwtPlotRasterItem::PaintCache )
00365     {
00366         // Caching doesn't make sense, when the item is
00367         // not painted to screen
00368 
00369         switch ( painter->paintEngine()->type() )
00370         {
00371             case QPaintEngine::SVG:
00372             case QPaintEngine::Pdf:
00373             case QPaintEngine::PostScript:
00374             case QPaintEngine::MacPrinter:
00375             case QPaintEngine::Picture:
00376                 break;
00377             default:;
00378                 doCache = true;
00379         }
00380     }
00381 
00382     return doCache;
00383 }
00384 
00385 static void qwtToRgba( const QImage* from, QImage* to,  
00386     const QRect& tile, int alpha )
00387 {
00388     const QRgb mask1 = qRgba( 0, 0, 0, alpha );
00389     const QRgb mask2 = qRgba( 255, 255, 255, 0 );
00390     const QRgb mask3 = qRgba( 0, 0, 0, 255 );
00391 
00392     const int y0 = tile.top();
00393     const int y1 = tile.bottom();
00394     const int x0 = tile.left();
00395     const int x1 = tile.right();
00396 
00397     if ( from->depth() == 8 )
00398     {
00399         for ( int y = y0; y <= y1; y++ )
00400         {
00401             QRgb *alphaLine = reinterpret_cast<QRgb *>( to->scanLine( y ) );
00402             const unsigned char *line = from->scanLine( y );
00403 
00404             for ( int x = x0; x <= x1; x++ )
00405                 *alphaLine++ = ( from->color( *line++ ) & mask2 ) | mask1;
00406         }
00407     }
00408     else if ( from->depth() == 32 )
00409     {
00410         for ( int y = y0; y <= y1; y++ )
00411         {
00412             QRgb *alphaLine = reinterpret_cast<QRgb *>( to->scanLine( y ) );
00413             const QRgb *line = reinterpret_cast<const QRgb *>( from->scanLine( y ) );
00414 
00415             for ( int x = x0; x <= x1; x++ )
00416             {
00417                 const QRgb rgb = *line++;
00418                 if ( rgb & mask3 ) // alpha != 0
00419                     *alphaLine++ = ( rgb & mask2 ) | mask1;
00420                 else
00421                     *alphaLine++ = rgb;
00422             }
00423         }
00424     }
00425 }
00426 
00428 QwtPlotRasterItem::QwtPlotRasterItem( const QString& title ):
00429     QwtPlotItem( QwtText( title ) )
00430 {
00431     init();
00432 }
00433 
00435 QwtPlotRasterItem::QwtPlotRasterItem( const QwtText& title ):
00436     QwtPlotItem( title )
00437 {
00438     init();
00439 }
00440 
00442 QwtPlotRasterItem::~QwtPlotRasterItem()
00443 {
00444     delete d_data;
00445 }
00446 
00447 void QwtPlotRasterItem::init()
00448 {
00449     d_data = new PrivateData();
00450 
00451     setItemAttribute( QwtPlotItem::AutoScale, true );
00452     setItemAttribute( QwtPlotItem::Legend, false );
00453 
00454     setZ( 8.0 );
00455 }
00456 
00464 void QwtPlotRasterItem::setPaintAttribute( PaintAttribute attribute, bool on )
00465 {
00466     if ( on )
00467         d_data->paintAttributes |= attribute;
00468     else
00469         d_data->paintAttributes &= ~attribute;
00470 }
00471 
00476 bool QwtPlotRasterItem::testPaintAttribute( PaintAttribute attribute ) const
00477 {
00478     return ( d_data->paintAttributes & attribute );
00479 }
00480 
00504 void QwtPlotRasterItem::setAlpha( int alpha )
00505 {
00506     if ( alpha < 0 )
00507         alpha = -1;
00508 
00509     if ( alpha > 255 )
00510         alpha = 255;
00511 
00512     if ( alpha != d_data->alpha )
00513     {
00514         d_data->alpha = alpha;
00515 
00516         itemChanged();
00517     }
00518 }
00519 
00524 int QwtPlotRasterItem::alpha() const
00525 {
00526     return d_data->alpha;
00527 }
00528 
00537 void QwtPlotRasterItem::setCachePolicy(
00538     QwtPlotRasterItem::CachePolicy policy )
00539 {
00540     if ( d_data->cache.policy != policy )
00541     {
00542         d_data->cache.policy = policy;
00543 
00544         invalidateCache();
00545         itemChanged();
00546     }
00547 }
00548 
00553 QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const
00554 {
00555     return d_data->cache.policy;
00556 }
00557 
00562 void QwtPlotRasterItem::invalidateCache()
00563 {
00564     d_data->cache.image = QImage();
00565     d_data->cache.area = QRect();
00566     d_data->cache.size = QSize();
00567 }
00568 
00595 QRectF QwtPlotRasterItem::pixelHint( const QRectF &area ) const
00596 {
00597     Q_UNUSED( area );
00598     return QRectF();
00599 }
00600 
00608 void QwtPlotRasterItem::draw( QPainter *painter,
00609     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00610     const QRectF &canvasRect ) const
00611 {
00612     if ( canvasRect.isEmpty() || d_data->alpha == 0 )
00613         return;
00614 
00615     const bool doCache = qwtUseCache( d_data->cache.policy, painter );
00616 
00617     const QwtInterval xInterval = interval( Qt::XAxis );
00618     const QwtInterval yInterval = interval( Qt::YAxis );
00619 
00620     /*
00621         Scaling an image always results in a loss of
00622         precision/quality. So we always render the image in
00623         paint device resolution.
00624     */
00625 
00626     QwtScaleMap xxMap, yyMap;
00627     qwtTransformMaps( painter->transform(), xMap, yMap, xxMap, yyMap );
00628 
00629     QRectF paintRect = painter->transform().mapRect( canvasRect );
00630     QRectF area = QwtScaleMap::invTransform( xxMap, yyMap, paintRect );
00631 
00632     const QRectF br = boundingRect();
00633     if ( br.isValid() && !br.contains( area ) )
00634     {
00635         area &= br;
00636         if ( !area.isValid() )
00637             return;
00638 
00639         paintRect = QwtScaleMap::transform( xxMap, yyMap, area );
00640     }
00641 
00642     QRectF imageRect;
00643     QImage image;
00644 
00645     QRectF pixelRect = pixelHint(area);
00646     if ( !pixelRect.isEmpty() )
00647     {
00648         // one pixel of the target device in plot coordinates
00649         const double dx = qAbs( xxMap.invTransform( 1 ) - xxMap.invTransform( 0 ) );
00650         const double dy = qAbs( yyMap.invTransform( 1 ) - yyMap.invTransform( 0 ) );
00651 
00652         if ( dx > pixelRect.width() && dy > pixelRect.height() )
00653         {
00654             /*
00655               When the resolution of the data pixels is higher than
00656               the resolution of the target device we render in
00657               target device resolution.
00658              */
00659             pixelRect = QRectF();
00660         }
00661         else
00662         {
00663             /*
00664               If only one dimension is of the data pixel is higher 
00665               we expand the pixel rect to the resolution of the target device.
00666              */
00667 
00668             if ( dx > pixelRect.width() )
00669                 pixelRect.setWidth( dx );
00670 
00671             if ( dy > pixelRect.height() )
00672                 pixelRect.setHeight( dy );
00673         }
00674     }
00675 
00676     if ( pixelRect.isEmpty() )
00677     {
00678         if ( QwtPainter::roundingAlignment( painter ) )
00679         {
00680             // we want to have maps, where the boundaries of
00681             // the aligned paint rectangle exactly match the area
00682 
00683             paintRect = qwtAlignRect(paintRect);
00684             qwtAdjustMaps(xxMap, yyMap, area, paintRect);
00685         }
00686 
00687         // When we have no information about position and size of
00688         // data pixels we render in resolution of the paint device.
00689 
00690         image = compose(xxMap, yyMap, 
00691             area, paintRect, paintRect.size().toSize(), doCache);
00692         if ( image.isNull() )
00693             return;
00694 
00695         // Remove pixels at the boundaries, when explicitly
00696         // excluded in the intervals
00697 
00698         imageRect = qwtStripRect(paintRect, area, 
00699             xxMap, yyMap, xInterval, yInterval);
00700 
00701         if ( imageRect != paintRect )
00702         {
00703             const QRect r( 
00704                 qRound( imageRect.x() - paintRect.x()),
00705                 qRound( imageRect.y() - paintRect.y() ),
00706                 qRound( imageRect.width() ),
00707                 qRound( imageRect.height() ) );
00708                 
00709             image = image.copy(r);
00710         }   
00711     }
00712     else
00713     {
00714         if ( QwtPainter::roundingAlignment( painter ) )
00715             paintRect = qwtAlignRect(paintRect);
00716 
00717         // align the area to the data pixels
00718         QRectF imageArea = qwtExpandToPixels(area, pixelRect);
00719 
00720         if ( imageArea.right() == xInterval.maxValue() &&
00721             !( xInterval.borderFlags() & QwtInterval::ExcludeMaximum ) )
00722         {
00723             imageArea.adjust(0, 0, pixelRect.width(), 0);
00724         }
00725         if ( imageArea.bottom() == yInterval.maxValue() &&
00726             !( yInterval.borderFlags() & QwtInterval::ExcludeMaximum ) )
00727         {
00728             imageArea.adjust(0, 0, 0, pixelRect.height() );
00729         }
00730 
00731         QSize imageSize;
00732         imageSize.setWidth( qRound( imageArea.width() / pixelRect.width() ) );
00733         imageSize.setHeight( qRound( imageArea.height() / pixelRect.height() ) );
00734 
00735         image = compose(xxMap, yyMap, 
00736             imageArea, paintRect, imageSize, doCache );
00737 
00738         if ( image.isNull() )
00739             return;
00740 
00741         imageRect = qwtStripRect(paintRect, area, 
00742             xxMap, yyMap, xInterval, yInterval);
00743 
00744         if ( ( image.width() > 1 || image.height() > 1 ) &&
00745             testPaintAttribute( PaintInDeviceResolution ) )
00746         {
00747             // Because of rounding errors the pixels 
00748             // need to be expanded manually to rectangles of 
00749             // different sizes
00750 
00751             image = qwtExpandImage(image, xxMap, yyMap, 
00752                 imageArea, area, paintRect, xInterval, yInterval );
00753         }
00754     }
00755 
00756     painter->save();
00757     painter->setWorldTransform( QTransform() );
00758     
00759     QwtPainter::drawImage( painter, imageRect, image );
00760 
00761     painter->restore();
00762 }
00763 
00772 QwtInterval QwtPlotRasterItem::interval(Qt::Axis axis) const
00773 {
00774     Q_UNUSED( axis );
00775     return QwtInterval();
00776 }
00777 
00782 QRectF QwtPlotRasterItem::boundingRect() const
00783 {
00784     const QwtInterval intervalX = interval( Qt::XAxis );
00785     const QwtInterval intervalY = interval( Qt::YAxis );
00786 
00787     if ( !intervalX.isValid() && !intervalY.isValid() )
00788         return QRectF(); // no bounding rect
00789 
00790     QRectF r;
00791 
00792     if ( intervalX.isValid() )
00793     {
00794         r.setLeft( intervalX.minValue() );
00795         r.setRight( intervalX.maxValue() );
00796     }
00797     else
00798     {
00799         r.setLeft(-0.5 * FLT_MAX);
00800         r.setWidth(FLT_MAX);
00801     }
00802 
00803     if ( intervalY.isValid() )
00804     {
00805         r.setTop( intervalY.minValue() );
00806         r.setBottom( intervalY.maxValue() );
00807     }
00808     else
00809     {
00810         r.setTop(-0.5 * FLT_MAX);
00811         r.setHeight(FLT_MAX);
00812     }
00813 
00814     return r.normalized();
00815 }
00816 
00817 QImage QwtPlotRasterItem::compose( 
00818     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00819     const QRectF &imageArea, const QRectF &paintRect, 
00820     const QSize &imageSize, bool doCache) const
00821 {
00822     QImage image;
00823     if ( imageArea.isEmpty() || paintRect.isEmpty() || imageSize.isEmpty() )
00824         return image;
00825 
00826     if ( doCache )
00827     {
00828         if ( !d_data->cache.image.isNull()
00829             && d_data->cache.area == imageArea
00830             && d_data->cache.size == paintRect.size() )
00831         {
00832             image = d_data->cache.image;
00833         }
00834     }
00835 
00836     if ( image.isNull() )
00837     {
00838         double dx = 0.0;
00839         if ( paintRect.toRect().width() > imageSize.width() )
00840             dx = imageArea.width() / imageSize.width();
00841 
00842         const QwtScaleMap xxMap = 
00843             imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx);
00844         
00845         double dy = 0.0;
00846         if ( paintRect.toRect().height() > imageSize.height() )
00847             dy = imageArea.height() / imageSize.height();
00848 
00849         const QwtScaleMap yyMap = 
00850             imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy);
00851 
00852         image = renderImage( xxMap, yyMap, imageArea, imageSize );
00853 
00854         if ( doCache )
00855         {
00856             d_data->cache.area = imageArea;
00857             d_data->cache.size = paintRect.size();
00858             d_data->cache.image = image;
00859         }
00860     }
00861 
00862     if ( d_data->alpha >= 0 && d_data->alpha < 255 )
00863     {
00864         QImage alphaImage( image.size(), QImage::Format_ARGB32 );
00865 
00866 #if !defined(QT_NO_QFUTURE)
00867         uint numThreads = renderThreadCount();
00868 
00869         if ( numThreads <= 0 )
00870             numThreads = QThread::idealThreadCount();
00871 
00872         if ( numThreads <= 0 )
00873             numThreads = 1;
00874 
00875         const int numRows = image.height() / numThreads;
00876 
00877         QList< QFuture<void> > futures;
00878         for ( uint i = 0; i < numThreads; i++ )
00879         {
00880             QRect tile( 0, i * numRows, image.width(), numRows );
00881             if ( i == numThreads - 1 )
00882             {
00883                 tile.setHeight( image.height() - i * numRows );
00884                 qwtToRgba( &image, &alphaImage, tile, d_data->alpha );
00885             }
00886             else
00887             {
00888                 futures += QtConcurrent::run(
00889                     &qwtToRgba, &image, &alphaImage, tile, d_data->alpha );
00890             }
00891         }
00892         for ( int i = 0; i < futures.size(); i++ )
00893             futures[i].waitForFinished();
00894 #else
00895         const QRect tile( 0, 0, image.width(), image.height() );
00896         qwtToRgba( &image, &alphaImage, tile, d_data->alpha );
00897 #endif
00898         image = alphaImage;
00899     }
00900 
00901     return image;
00902 }
00903 
00915 QwtScaleMap QwtPlotRasterItem::imageMap(
00916     Qt::Orientation orientation,
00917     const QwtScaleMap &map, const QRectF &area,
00918     const QSize &imageSize, double pixelSize) const
00919 {
00920     double p1, p2, s1, s2;
00921 
00922     if ( orientation == Qt::Horizontal )
00923     {
00924         p1 = 0.0;
00925         p2 = imageSize.width();
00926         s1 = area.left();
00927         s2 = area.right();
00928     }
00929     else
00930     {
00931         p1 = 0.0;
00932         p2 = imageSize.height();
00933         s1 = area.top();
00934         s2 = area.bottom();
00935     }
00936 
00937     if ( pixelSize > 0.0 )
00938     {
00939         double off = 0.5 * pixelSize;
00940         if ( map.isInverting() )
00941             off = -off;
00942 
00943         s1 += off;
00944         s2 += off;
00945     }
00946     else
00947     {
00948         p2--;
00949     }
00950 
00951     if ( map.isInverting() && ( s1 < s2 ) )
00952         qSwap( s1, s2 );
00953 
00954     QwtScaleMap newMap = map;
00955     newMap.setPaintInterval( p1, p2 );
00956     newMap.setScaleInterval( s1, s2 );
00957 
00958     return newMap;
00959 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56