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> 
   25 class QwtPlotRasterItem::PrivateData
 
   49 static 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() ) );
 
   60 static 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);
 
  112 static 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 );
 
  309 static 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 );
 
  328 static 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:
 
  391 static 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;
 
  453 void 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);
 
  696         image = compose(xxMap, yyMap,
 
  698         if ( image.isNull() )
 
  704         imageRect = qwtStripRect(
paintRect, area,
 
  705             xxMap, yyMap, xInterval, yInterval);
 
  712                 qRound( imageRect.width() ),
 
  713                 qRound( imageRect.height() ) );
 
  715             image = image.copy(r);
 
  724         QRectF imageArea = qwtExpandToPixels(area, pixelRect);
 
  726         if ( imageArea.right() == xInterval.
maxValue() &&
 
  729             imageArea.adjust(0, 0, pixelRect.width(), 0);
 
  731         if ( imageArea.bottom() == yInterval.
maxValue() &&
 
  734             imageArea.adjust(0, 0, 0, pixelRect.height() );
 
  738         imageSize.setWidth( qRound( imageArea.width() / pixelRect.width() ) );
 
  739         imageSize.setHeight( qRound( imageArea.height() / pixelRect.height() ) );
 
  741         image = compose(xxMap, yyMap,
 
  742             imageArea, 
paintRect, imageSize, doCache );
 
  744         if ( image.isNull() )
 
  747         imageRect = qwtStripRect(
paintRect, area,
 
  748             xxMap, yyMap, xInterval, yInterval);
 
  750         if ( ( image.width() > 1 || image.height() > 1 ) &&
 
  757             image = qwtExpandImage(image, xxMap, yyMap,
 
  758                 imageArea, area, 
paintRect, xInterval, yInterval );
 
  763     painter->setWorldTransform( QTransform() );
 
  805         const qreal max = std::numeric_limits< float >::max();
 
  807         r.setLeft( -0.5 * max );
 
  814         r.setBottom( intervalY.
maxValue() );
 
  818         const qreal max = std::numeric_limits< float >::max();
 
  820         r.setTop( -0.5 * max );
 
  824     return r.normalized();
 
  827 QImage QwtPlotRasterItem::compose(
 
  829     const QRectF& imageArea, 
const QRectF& paintRect,
 
  830     const QSize& imageSize, 
bool doCache)
 const 
  833     if ( imageArea.isEmpty() || 
paintRect.isEmpty() || imageSize.isEmpty() )
 
  838         if ( !m_data->cache.image.isNull()
 
  839             && m_data->cache.area == imageArea
 
  840             && m_data->cache.size == 
paintRect.size() )
 
  842             image = m_data->cache.image;
 
  846     if ( image.isNull() )
 
  849         if ( 
paintRect.toRect().width() > imageSize.width() )
 
  850             dx = imageArea.width() / imageSize.width();
 
  853             imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx);
 
  856         if ( 
paintRect.toRect().height() > imageSize.height() )
 
  857             dy = imageArea.height() / imageSize.height();
 
  860             imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy);
 
  862         image = 
renderImage( xxMap, yyMap, imageArea, imageSize );
 
  866             m_data->cache.area = imageArea;
 
  868             m_data->cache.image = image;
 
  872     if ( m_data->alpha >= 0 && m_data->alpha < 255 )
 
  874         QImage alphaImage( image.size(), QImage::Format_ARGB32 );
 
  876 #if !defined( QT_NO_QFUTURE ) 
  879         if ( numThreads <= 0 )
 
  880             numThreads = QThread::idealThreadCount();
 
  882         if ( numThreads <= 0 )
 
  885         const int numRows = image.height() / numThreads;
 
  888         futures.reserve( numThreads - 1 );
 
  890         for ( uint i = 0; i < numThreads; i++ )
 
  892             QRect tile( 0, i * numRows, image.width(), numRows );
 
  893             if ( i == numThreads - 1 )
 
  895                 tile.setHeight( image.height() - i * numRows );
 
  896                 qwtToRgba( &image, &alphaImage, tile, m_data->alpha );
 
  900                 futures += QtConcurrent::run(
 
  901                     &qwtToRgba, &image, &alphaImage, tile, m_data->alpha );
 
  904         for ( 
int i = 0; i < futures.size(); i++ )
 
  905             futures[i].waitForFinished();
 
  907         const QRect tile( 0, 0, image.width(), image.height() );
 
  908         qwtToRgba( &image, &alphaImage, tile, m_data->alpha );
 
  928     Qt::Orientation orientation,
 
  930     const QSize& imageSize, 
double pixelSize)
 const 
  932     double p1, p2, s1, s2;
 
  934     if ( orientation == Qt::Horizontal )
 
  937         p2 = imageSize.width();
 
  944         p2 = imageSize.height();
 
  949     if ( pixelSize > 0.0 || p2 == 1.0 )
 
  951         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 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.