10#include "qwt_plot_rasteritem.h" 
   11#include "qwt_scale_map.h" 
   12#include "qwt_painter.h" 
   14#include "qwt_interval.h" 
   18#include <qpaintengine.h> 
   21#include <qtconcurrentrun.h> 
   25class QwtPlotRasterItem::PrivateData
 
   49static QRectF qwtAlignRect(
const QRectF& rect)
 
   52    r.setLeft( qRound( rect.left() ) );
 
   53    r.setRight( qRound( rect.right() ) );
 
   54    r.setTop( qRound( rect.top() ) );
 
   55    r.setBottom( qRound( rect.bottom() ) );
 
   60static QRectF qwtStripRect(
const QRectF& rect, 
const QRectF& area,
 
   67        if ( area.left() <= xInterval.
minValue() )
 
   70                r.adjust(0, 0, -1, 0);
 
   78        if ( area.right() >= xInterval.
maxValue() )
 
   83                r.adjust(0, 0, -1, 0);
 
   89        if ( area.top() <= yInterval.
minValue() )
 
   92                r.adjust(0, 0, 0, -1);
 
  100        if ( area.bottom() >= yInterval.
maxValue() )
 
  103                r.adjust(0, 1, 0, 0);
 
  105                r.adjust(0, 0, 0, -1);
 
  112static QImage qwtExpandImage(
const QImage& image,
 
  114    const QRectF& area, 
const QRectF& area2, 
const QRectF& paintRect,
 
  117    const QRectF strippedRect = qwtStripRect(paintRect, area2,
 
  118        xMap, yMap, xInterval, yInterval);
 
  119    const QSize sz = strippedRect.toRect().size();
 
  121    const int w = image.width();
 
  122    const int h = image.height();
 
  125    const double pw = ( r.width() - 1 ) / w;
 
  126    const double ph = ( r.height() - 1 ) / h;
 
  133        px0 = px0 - xMap.
transform( area.left() );
 
  143    px0 += strippedRect.left() - paintRect.left();
 
  159    py0 += strippedRect.top() - paintRect.top();
 
  161    QImage expanded( sz, image.format() );
 
  162    if ( image.format() == QImage::Format_Indexed8 )
 
  163        expanded.setColorTable( image.colorTable() );
 
  165    switch( image.depth() )
 
  169            for ( 
int y1 = 0; y1 < h; y1++ )
 
  178                    yy1 = qRound( y1 * ph - py0 );
 
  190                    yy2 = qRound( ( y1 + 1 ) * ph - py0 );
 
  191                    if ( yy2 > sz.height() )
 
  195                const quint32* line1 =
 
  196                    reinterpret_cast< const quint32* 
>( image.scanLine( y1 ) );
 
  198                for ( 
int x1 = 0; x1 < w; x1++ )
 
  207                        xx1 = qRound( x1 * pw - px0 );
 
  219                        xx2 = qRound( ( x1 + 1 ) * pw - px0 );
 
  220                        if ( xx2 > sz.width() )
 
  224                    const quint32 rgb( line1[x1] );
 
  225                    for ( 
int y2 = yy1; y2 < yy2; y2++ )
 
  227                        quint32* line2 = 
reinterpret_cast< quint32* 
>(
 
  228                            expanded.scanLine( y2 ) );
 
  230                        for ( 
int x2 = xx1; x2 < xx2; x2++ )
 
  239            for ( 
int y1 = 0; y1 < h; y1++ )
 
  248                    yy1 = qRound( y1 * ph - py0 );
 
  260                    yy2 = qRound( ( y1 + 1 ) * ph - py0 );
 
  261                    if ( yy2 > sz.height() )
 
  265                const uchar* line1 = image.scanLine( y1 );
 
  267                for ( 
int x1 = 0; x1 < w; x1++ )
 
  276                        xx1 = qRound( x1 * pw - px0 );
 
  288                        xx2 = qRound( ( x1 + 1 ) * pw - px0 );
 
  289                        if ( xx2 > sz.width() )
 
  293                    for ( 
int y2 = yy1; y2 < yy2; y2++ )
 
  295                        uchar* line2 = expanded.scanLine( y2 );
 
  296                        memset( line2 + xx1, line1[x1], xx2 - xx1 );
 
  309static QRectF qwtExpandToPixels(
const QRectF& rect, 
const QRectF& pixelRect)
 
  311    const double pw = pixelRect.width();
 
  312    const double ph = pixelRect.height();
 
  314    const double dx1 = pixelRect.left() - rect.left();
 
  315    const double dx2 = pixelRect.right() - rect.right();
 
  316    const double dy1 = pixelRect.top() - rect.top();
 
  317    const double dy2 = pixelRect.bottom() - rect.bottom();
 
  320    r.setLeft( pixelRect.left() - qwtCeil( dx1 / pw ) * pw );
 
  321    r.setTop( pixelRect.top() - qwtCeil( dy1 / ph ) * ph );
 
  322    r.setRight( pixelRect.right() - qwtFloor( dx2 / pw ) * pw );
 
  323    r.setBottom( pixelRect.bottom() - qwtFloor( dy2 / ph ) * ph );
 
  328static void qwtTransformMaps( 
const QTransform& tr,
 
  332    const QPointF p1 = tr.map( QPointF( xMap.
p1(), yMap.
p1() ) );
 
  333    const QPointF p2 = tr.map( QPointF( xMap.
p2(), yMap.
p2() ) );
 
  343    const QRectF& area, 
const QRectF& paintRect)
 
  345    double sx1 = area.left();
 
  346    double sx2 = area.right();
 
  350    double sy1 = area.top();
 
  351    double sy2 = area.bottom();
 
  364    const QPainter* painter )
 
  366    bool doCache = 
false;
 
  373        switch ( painter->paintEngine()->type() )
 
  375            case QPaintEngine::SVG:
 
  376            case QPaintEngine::Pdf:
 
  377#if QT_VERSION < 0x060000 
  378            case QPaintEngine::PostScript:
 
  380            case QPaintEngine::MacPrinter:
 
  381            case QPaintEngine::Picture:
 
  391static void qwtToRgba( 
const QImage* from, QImage* to,
 
  392    const QRect& tile, 
int alpha )
 
  394    const QRgb mask1 = qRgba( 0, 0, 0, alpha );
 
  395    const QRgb mask2 = qRgba( 255, 255, 255, 0 );
 
  396    const QRgb mask3 = qRgba( 0, 0, 0, 255 );
 
  398    const int y0 = tile.top();
 
  399    const int y1 = tile.bottom();
 
  400    const int x0 = tile.left();
 
  401    const int x1 = tile.right();
 
  403    if ( from->depth() == 8 )
 
  405        for ( 
int y = y0; y <= y1; y++ )
 
  407            QRgb* alphaLine = 
reinterpret_cast< QRgb* 
>( to->scanLine( y ) );
 
  408            const unsigned char* line = from->scanLine( y );
 
  410            for ( 
int x = x0; x <= x1; x++ )
 
  411                *alphaLine++ = ( from->color( *line++ ) & mask2 ) | mask1;
 
  414    else if ( from->depth() == 32 )
 
  416        for ( 
int y = y0; y <= y1; y++ )
 
  418            QRgb* alphaLine = 
reinterpret_cast< QRgb* 
>( to->scanLine( y ) );
 
  419            const QRgb* line = 
reinterpret_cast< const QRgb* 
>( from->scanLine( y ) );
 
  421            for ( 
int x = x0; x <= x1; x++ )
 
  423                const QRgb rgb = *line++;
 
  425                    *alphaLine++ = ( rgb & mask2 ) | mask1;
 
  453void QwtPlotRasterItem::init()
 
  455    m_data = 
new PrivateData();
 
  473        m_data->paintAttributes |= attribute;
 
  475        m_data->paintAttributes &= ~attribute;
 
 
  484    return ( m_data->paintAttributes & attribute );
 
 
  518    if ( 
alpha != m_data->alpha )
 
  520        m_data->alpha = 
alpha;
 
 
  532    return m_data->alpha;
 
 
  546    if ( m_data->cache.policy != policy )
 
  548        m_data->cache.policy = policy;
 
 
  561    return m_data->cache.policy;
 
 
  570    m_data->cache.image = QImage();
 
  571    m_data->cache.area = QRect();
 
  572    m_data->cache.size = QSize();
 
 
  616    const QRectF& canvasRect )
 const 
  618    if ( canvasRect.isEmpty() || m_data->alpha == 0 )
 
  621    const bool doCache = qwtUseCache( m_data->cache.policy, painter );
 
  633    qwtTransformMaps( painter->transform(), xMap, yMap, xxMap, yyMap );
 
  635    QRectF 
paintRect = painter->transform().mapRect( canvasRect );
 
  639    if ( br.isValid() && !br.contains( area ) )
 
  642        if ( !area.isValid() )
 
  652    if ( !pixelRect.isEmpty() )
 
  658        if ( dx > pixelRect.width() && dy > pixelRect.height() )
 
  665            pixelRect = QRectF();
 
  674            if ( dx > pixelRect.width() )
 
  675                pixelRect.setWidth( dx );
 
  677            if ( dy > pixelRect.height() )
 
  678                pixelRect.setHeight( dy );
 
  682    if ( pixelRect.isEmpty() )
 
  690            qwtAdjustMaps(xxMap, yyMap, area, 
paintRect);
 
  698#if QT_VERSION >= 0x050000 
  700        imageSize *= pixelRatio;
 
  703        image = compose(xxMap, yyMap,
 
  704            area, 
paintRect, imageSize.toSize(), doCache);
 
  706        if ( image.isNull() )
 
  709#if QT_VERSION >= 0x050000 
  710        image.setDevicePixelRatio( pixelRatio );
 
  716        imageRect = qwtStripRect(
paintRect, area,
 
  717            xxMap, yyMap, xInterval, yInterval);
 
  724                qRound( imageRect.width() ),
 
  725                qRound( imageRect.height() ) );
 
  727            image = image.copy(r);
 
  736        QRectF imageArea = qwtExpandToPixels(area, pixelRect);
 
  738        if ( imageArea.right() == xInterval.
maxValue() &&
 
  741            imageArea.adjust(0, 0, pixelRect.width(), 0);
 
  743        if ( imageArea.bottom() == yInterval.
maxValue() &&
 
  746            imageArea.adjust(0, 0, 0, pixelRect.height() );
 
  750        imageSize.setWidth( qRound( imageArea.width() / pixelRect.width() ) );
 
  751        imageSize.setHeight( qRound( imageArea.height() / pixelRect.height() ) );
 
  753        image = compose(xxMap, yyMap,
 
  754            imageArea, 
paintRect, imageSize, doCache );
 
  756        if ( image.isNull() )
 
  759        imageRect = qwtStripRect(
paintRect, area,
 
  760            xxMap, yyMap, xInterval, yInterval);
 
  762        if ( ( image.width() > 1 || image.height() > 1 ) &&
 
  769            image = qwtExpandImage(image, xxMap, yyMap,
 
  770                imageArea, area, 
paintRect, xInterval, yInterval );
 
  775    painter->setWorldTransform( QTransform() );
 
 
  817        const qreal max = std::numeric_limits< float >::max();
 
  819        r.setLeft( -0.5 * max );
 
  826        r.setBottom( intervalY.
maxValue() );
 
  830        const qreal max = std::numeric_limits< float >::max();
 
  832        r.setTop( -0.5 * max );
 
  836    return r.normalized();
 
 
  839QImage QwtPlotRasterItem::compose(
 
  841    const QRectF& imageArea, 
const QRectF& paintRect,
 
  842    const QSize& imageSize, 
bool doCache)
 const 
  845    if ( imageArea.isEmpty() || 
paintRect.isEmpty() || imageSize.isEmpty() )
 
  850        if ( !m_data->cache.image.isNull()
 
  851            && m_data->cache.area == imageArea
 
  852            && m_data->cache.size == 
paintRect.size() )
 
  854            image = m_data->cache.image;
 
  858    if ( image.isNull() )
 
  861        if ( 
paintRect.toRect().width() > imageSize.width() )
 
  862            dx = imageArea.width() / imageSize.width();
 
  865            imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx);
 
  868        if ( 
paintRect.toRect().height() > imageSize.height() )
 
  869            dy = imageArea.height() / imageSize.height();
 
  872            imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy);
 
  874        image = 
renderImage( xxMap, yyMap, imageArea, imageSize );
 
  878            m_data->cache.area = imageArea;
 
  880            m_data->cache.image = image;
 
  884    if ( m_data->alpha >= 0 && m_data->alpha < 255 )
 
  886        QImage alphaImage( image.size(), QImage::Format_ARGB32 );
 
  888#if !defined( QT_NO_QFUTURE ) 
  891        if ( numThreads <= 0 )
 
  892            numThreads = QThread::idealThreadCount();
 
  894        if ( numThreads <= 0 )
 
  897        const int numRows = image.height() / numThreads;
 
  900        futures.reserve( numThreads - 1 );
 
  902        for ( uint i = 0; i < numThreads; i++ )
 
  904            QRect tile( 0, i * numRows, image.width(), numRows );
 
  905            if ( i == numThreads - 1 )
 
  907                tile.setHeight( image.height() - i * numRows );
 
  908                qwtToRgba( &image, &alphaImage, tile, m_data->alpha );
 
  912                futures += QtConcurrent::run(
 
  913                    &qwtToRgba, &image, &alphaImage, tile, m_data->alpha );
 
  916        for ( 
int i = 0; i < futures.size(); i++ )
 
  917            futures[i].waitForFinished();
 
  919        const QRect tile( 0, 0, image.width(), image.height() );
 
  920        qwtToRgba( &image, &alphaImage, tile, m_data->alpha );
 
  940    Qt::Orientation orientation,
 
  942    const QSize& imageSize, 
double pixelSize)
 const 
  944    double p1, p2, s1, s2;
 
  946    if ( orientation == Qt::Horizontal )
 
  949        p2 = imageSize.width();
 
  956        p2 = imageSize.height();
 
  961    if ( pixelSize > 0.0 || p2 == 1.0 )
 
  963        double off = 0.5 * pixelSize;
 
 
A class representing an interval.
@ ExcludeMaximum
Max value is not included in the interval.
@ ExcludeMinimum
Min value is not included in the interval.
BorderFlags borderFlags() const
static void drawImage(QPainter *, const QRectF &, const QImage &)
Wrapper for QPainter::drawImage()
static qreal devicePixelRatio(const QPaintDevice *)
static bool roundingAlignment()
Base class for items on the plot canvas.
QRectF paintRect(const QwtScaleMap &, const QwtScaleMap &) const
Calculate the bounding paint rectangle of 2 maps.
void setZ(double z)
Set the z value.
void setItemAttribute(ItemAttribute, bool on=true)
virtual void itemChanged()
@ Legend
The item is represented on the legend.
uint renderThreadCount() const
A class, which displays raster data.
bool testPaintAttribute(PaintAttribute) const
virtual void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const override
Draw the raster data.
virtual QRectF boundingRect() const override
void setAlpha(int alpha)
Set an alpha value for the raster data.
virtual QImage renderImage(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize) const =0
Render an image.
virtual ~QwtPlotRasterItem()
Destructor.
void setCachePolicy(CachePolicy)
void setPaintAttribute(PaintAttribute, bool on=true)
QFlags< PaintAttribute > PaintAttributes
@ PaintInDeviceResolution
virtual QRectF pixelHint(const QRectF &) const
Pixel hint.
CachePolicy
Cache policy The default policy is NoCache.
QwtPlotRasterItem(const QString &title=QString())
Constructor.
virtual QwtScaleMap imageMap(Qt::Orientation, const QwtScaleMap &map, const QRectF &area, const QSize &imageSize, double pixelSize) const
Calculate a scale map for painting to an image.
virtual QwtInterval interval(Qt::Axis) const
CachePolicy cachePolicy() const
double transform(double s) const
void setPaintInterval(double p1, double p2)
Specify the borders of the paint device interval.
void setScaleInterval(double s1, double s2)
Specify the borders of the scale interval.
double invTransform(double p) const
A class representing a text.