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.