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.