source: ntrip/trunk/BNC/qwt/qwt_plot_rasteritem.cpp@ 7905

Last change on this file since 7905 was 4271, checked in by mervart, 12 years ago
File size: 23.6 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_plot_rasteritem.h"
11#include "qwt_legend.h"
12#include "qwt_legend_item.h"
13#include "qwt_scale_map.h"
14#include "qwt_painter.h"
15#include <qapplication.h>
16#include <qdesktopwidget.h>
17#include <qpainter.h>
18#include <qpaintengine.h>
19#include <float.h>
20
21class QwtPlotRasterItem::PrivateData
22{
23public:
24 PrivateData():
25 alpha( -1 ),
26 paintAttributes( QwtPlotRasterItem::PaintInDeviceResolution )
27 {
28 cache.policy = QwtPlotRasterItem::NoCache;
29 }
30
31 int alpha;
32 QwtPlotRasterItem::PaintAttributes paintAttributes;
33
34 struct ImageCache
35 {
36 QwtPlotRasterItem::CachePolicy policy;
37 QRectF area;
38 QSizeF size;
39 QImage image;
40 } cache;
41};
42
43
44static QRectF qwtAlignRect(const QRectF &rect)
45{
46 QRectF r;
47 r.setLeft( qRound( rect.left() ) );
48 r.setRight( qRound( rect.right() ) );
49 r.setTop( qRound( rect.top() ) );
50 r.setBottom( qRound( rect.bottom() ) );
51
52 return r;
53}
54
55static QRectF qwtStripRect(const QRectF &rect, const QRectF &area,
56 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
57 const QwtInterval &xInterval, const QwtInterval &yInterval)
58{
59 QRectF r = rect;
60 if ( xInterval.borderFlags() & QwtInterval::ExcludeMinimum )
61 {
62 if ( area.left() <= xInterval.minValue() )
63 {
64 if ( xMap.isInverting() )
65 r.adjust(0, 0, -1, 0);
66 else
67 r.adjust(1, 0, 0, 0);
68 }
69 }
70
71 if ( xInterval.borderFlags() & QwtInterval::ExcludeMaximum )
72 {
73 if ( area.right() >= xInterval.maxValue() )
74 {
75 if ( xMap.isInverting() )
76 r.adjust(1, 0, 0, 0);
77 else
78 r.adjust(0, 0, -1, 0);
79 }
80 }
81
82 if ( yInterval.borderFlags() & QwtInterval::ExcludeMinimum )
83 {
84 if ( area.top() <= yInterval.minValue() )
85 {
86 if ( yMap.isInverting() )
87 r.adjust(0, 0, 0, -1);
88 else
89 r.adjust(0, 1, 0, 0);
90 }
91 }
92
93 if ( yInterval.borderFlags() & QwtInterval::ExcludeMaximum )
94 {
95 if ( area.bottom() >= yInterval.maxValue() )
96 {
97 if ( yMap.isInverting() )
98 r.adjust(0, 1, 0, 0);
99 else
100 r.adjust(0, 0, 0, -1);
101 }
102 }
103
104 return r;
105}
106
107static QImage qwtExpandImage(const QImage &image,
108 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
109 const QRectF &area, const QRectF &area2, const QRectF &paintRect,
110 const QwtInterval &xInterval, const QwtInterval &yInterval )
111{
112 const QRectF strippedRect = qwtStripRect(paintRect, area2,
113 xMap, yMap, xInterval, yInterval);
114 const QSize sz = strippedRect.toRect().size();
115
116 const int w = image.width();
117 const int h = image.height();
118
119 const QRectF r = QwtScaleMap::transform(xMap, yMap, area).normalized();
120 const double pw = ( r.width() - 1) / w;
121 const double ph = ( r.height() - 1) / h;
122
123 double px0, py0;
124 if ( !xMap.isInverting() )
125 {
126 px0 = xMap.transform( area2.left() );
127 px0 = qRound( px0 );
128 px0 = px0 - xMap.transform( area.left() );
129 }
130 else
131 {
132 px0 = xMap.transform( area2.right() );
133 px0 = qRound( px0 );
134 px0 -= xMap.transform( area.right() );
135
136 px0 -= 1.0;
137 }
138 px0 += strippedRect.left() - paintRect.left();
139
140 if ( !yMap.isInverting() )
141 {
142 py0 = yMap.transform( area2.top() );
143 py0 = qRound( py0 );
144 py0 -= yMap.transform( area.top() );
145 }
146 else
147 {
148 py0 = yMap.transform( area2.bottom() );
149 py0 = qRound( py0 );
150 py0 -= yMap.transform( area.bottom() );
151
152 py0 -= 1.0;
153 }
154 py0 += strippedRect.top() - paintRect.top();
155
156 QImage expanded(sz, image.format());
157
158 switch( image.depth() )
159 {
160 case 32:
161 {
162 for ( int y1 = 0; y1 < h; y1++ )
163 {
164 int yy1;
165 if ( y1 == 0 )
166 {
167 yy1 = 0;
168 }
169 else
170 {
171 yy1 = qRound( y1 * ph - py0 );
172 if ( yy1 < 0 )
173 yy1 = 0;
174 }
175
176 int yy2;
177 if ( y1 == h - 1 )
178 {
179 yy2 = sz.height();
180 }
181 else
182 {
183 yy2 = qRound( ( y1 + 1 ) * ph - py0 );
184 if ( yy2 > sz.height() )
185 yy2 = sz.height();
186 }
187
188 const quint32 *line1 = (const quint32 *) image.scanLine( y1 );
189
190 for ( int x1 = 0; x1 < w; x1++ )
191 {
192 int xx1;
193 if ( x1 == 0 )
194 {
195 xx1 = 0;
196 }
197 else
198 {
199 xx1 = qRound( x1 * pw - px0 );
200 if ( xx1 < 0 )
201 xx1 = 0;
202 }
203
204 int xx2;
205 if ( x1 == w - 1 )
206 {
207 xx2 = sz.width();
208 }
209 else
210 {
211 xx2 = qRound( ( x1 + 1 ) * pw - px0 );
212 if ( xx2 > sz.width() )
213 xx2 = sz.width();
214 }
215
216 const quint32 rgb( line1[x1] );
217 for ( int y2 = yy1; y2 < yy2; y2++ )
218 {
219 quint32 *line2 = ( quint32 *) expanded.scanLine( y2 );
220 for ( int x2 = xx1; x2 < xx2; x2++ )
221 line2[x2] = rgb;
222 }
223 }
224 }
225 break;
226 }
227 case 8:
228 {
229 for ( int y1 = 0; y1 < h; y1++ )
230 {
231 int yy1;
232 if ( y1 == 0 )
233 {
234 yy1 = 0;
235 }
236 else
237 {
238 yy1 = qRound( y1 * ph - py0 );
239 if ( yy1 < 0 )
240 yy1 = 0;
241 }
242
243 int yy2;
244 if ( y1 == h - 1 )
245 {
246 yy2 = sz.height();
247 }
248 else
249 {
250 yy2 = qRound( ( y1 + 1 ) * ph - py0 );
251 if ( yy2 > sz.height() )
252 yy2 = sz.height();
253 }
254
255 const uchar *line1 = image.scanLine( y1 );
256
257 for ( int x1 = 0; x1 < w; x1++ )
258 {
259 int xx1;
260 if ( x1 == 0 )
261 {
262 xx1 = 0;
263 }
264 else
265 {
266 xx1 = qRound( x1 * pw - px0 );
267 if ( xx1 < 0 )
268 xx1 = 0;
269 }
270
271 int xx2;
272 if ( x1 == w - 1 )
273 {
274 xx2 = sz.width();
275 }
276 else
277 {
278 xx2 = qRound( ( x1 + 1 ) * pw - px0 );
279 if ( xx2 > sz.width() )
280 xx2 = sz.width();
281 }
282
283 for ( int y2 = yy1; y2 < yy2; y2++ )
284 {
285 uchar *line2 = expanded.scanLine( y2 );
286 memset( line2 + xx1, line1[x1], xx2 - xx1 );
287 }
288 }
289 }
290 break;
291 }
292 default:
293 expanded = image;
294 }
295
296 return expanded;
297}
298
299static QRectF expandToPixels(const QRectF &rect, const QRectF &pixelRect)
300{
301 const double pw = pixelRect.width();
302 const double ph = pixelRect.height();
303
304 const double dx1 = pixelRect.left() - rect.left();
305 const double dx2 = pixelRect.right() - rect.right();
306 const double dy1 = pixelRect.top() - rect.top();
307 const double dy2 = pixelRect.bottom() - rect.bottom();
308
309 QRectF r;
310 r.setLeft( pixelRect.left() - qCeil( dx1 / pw ) * pw );
311 r.setTop( pixelRect.top() - qCeil( dy1 / ph ) * ph );
312 r.setRight( pixelRect.right() - qFloor( dx2 / pw ) * pw );
313 r.setBottom( pixelRect.bottom() - qFloor( dy2 / ph ) * ph );
314
315 return r;
316}
317
318static void transformMaps( const QTransform &tr,
319 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
320 QwtScaleMap &xxMap, QwtScaleMap &yyMap )
321{
322 const QPointF p1 = tr.map( QPointF( xMap.p1(), yMap.p1() ) );
323 const QPointF p2 = tr.map( QPointF( xMap.p2(), yMap.p2() ) );
324
325 xxMap = xMap;
326 xxMap.setPaintInterval( p1.x(), p2.x() );
327
328 yyMap = yMap;
329 yyMap.setPaintInterval( p1.y(), p2.y() );
330}
331
332static void adjustMaps( QwtScaleMap &xMap, QwtScaleMap &yMap,
333 const QRectF &area, const QRectF &paintRect)
334{
335 double sx1 = area.left();
336 double sx2 = area.right();
337 if ( xMap.isInverting() )
338 qSwap(sx1, sx2);
339
340 double sy1 = area.top();
341 double sy2 = area.bottom();
342
343 if ( yMap.isInverting() )
344 qSwap(sy1, sy2);
345
346 xMap.setPaintInterval(paintRect.left(), paintRect.right());
347 xMap.setScaleInterval(sx1, sx2);
348
349 yMap.setPaintInterval(paintRect.top(), paintRect.bottom());
350 yMap.setScaleInterval(sy1, sy2);
351}
352
353static bool useCache( QwtPlotRasterItem::CachePolicy policy,
354 const QPainter *painter )
355{
356 bool doCache = false;
357
358 if ( policy == QwtPlotRasterItem::PaintCache )
359 {
360 // Caching doesn't make sense, when the item is
361 // not painted to screen
362
363 switch ( painter->paintEngine()->type() )
364 {
365 case QPaintEngine::SVG:
366 case QPaintEngine::Pdf:
367 case QPaintEngine::PostScript:
368 case QPaintEngine::MacPrinter:
369 case QPaintEngine::Picture:
370 break;
371 default:;
372 doCache = true;
373 }
374 }
375
376 return doCache;
377}
378
379static QImage toRgba( const QImage& image, int alpha )
380{
381 if ( alpha < 0 || alpha >= 255 )
382 return image;
383
384 QImage alphaImage( image.size(), QImage::Format_ARGB32 );
385
386 const QRgb mask1 = qRgba( 0, 0, 0, alpha );
387 const QRgb mask2 = qRgba( 255, 255, 255, 0 );
388 const QRgb mask3 = qRgba( 0, 0, 0, 255 );
389
390 const int w = image.size().width();
391 const int h = image.size().height();
392
393 if ( image.depth() == 8 )
394 {
395 for ( int y = 0; y < h; y++ )
396 {
397 QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y );
398 const unsigned char *line = image.scanLine( y );
399
400 for ( int x = 0; x < w; x++ )
401 *alphaLine++ = ( image.color( *line++ ) & mask2 ) | mask1;
402 }
403 }
404 else if ( image.depth() == 32 )
405 {
406 for ( int y = 0; y < h; y++ )
407 {
408 QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y );
409 const QRgb* line = ( const QRgb* ) image.scanLine( y );
410
411 for ( int x = 0; x < w; x++ )
412 {
413 const QRgb rgb = *line++;
414 if ( rgb & mask3 ) // alpha != 0
415 *alphaLine++ = ( rgb & mask2 ) | mask1;
416 else
417 *alphaLine++ = rgb;
418 }
419 }
420 }
421
422 return alphaImage;
423}
424
425//! Constructor
426QwtPlotRasterItem::QwtPlotRasterItem( const QString& title ):
427 QwtPlotItem( QwtText( title ) )
428{
429 init();
430}
431
432//! Constructor
433QwtPlotRasterItem::QwtPlotRasterItem( const QwtText& title ):
434 QwtPlotItem( title )
435{
436 init();
437}
438
439//! Destructor
440QwtPlotRasterItem::~QwtPlotRasterItem()
441{
442 delete d_data;
443}
444
445void QwtPlotRasterItem::init()
446{
447 d_data = new PrivateData();
448
449 setItemAttribute( QwtPlotItem::AutoScale, true );
450 setItemAttribute( QwtPlotItem::Legend, false );
451
452 setZ( 8.0 );
453}
454
455/*!
456 Specify an attribute how to draw the raster item
457
458 \param attribute Paint attribute
459 \param on On/Off
460 /sa PaintAttribute, testPaintAttribute()
461*/
462void QwtPlotRasterItem::setPaintAttribute( PaintAttribute attribute, bool on )
463{
464 if ( on )
465 d_data->paintAttributes |= attribute;
466 else
467 d_data->paintAttributes &= ~attribute;
468}
469
470/*!
471 \brief Return the current paint attributes
472 \sa PaintAttribute, setPaintAttribute()
473*/
474bool QwtPlotRasterItem::testPaintAttribute( PaintAttribute attribute ) const
475{
476 return ( d_data->paintAttributes & attribute );
477}
478
479/*!
480 \brief Set an alpha value for the raster data
481
482 Often a plot has several types of raster data organized in layers.
483 ( f.e a geographical map, with weather statistics ).
484 Using setAlpha() raster items can be stacked easily.
485
486 The alpha value is a value [0, 255] to
487 control the transparency of the image. 0 represents a fully
488 transparent color, while 255 represents a fully opaque color.
489
490 \param alpha Alpha value
491
492 - alpha >= 0\n
493 All alpha values of the pixels returned by renderImage() will be set to
494 alpha, beside those with an alpha value of 0 (invalid pixels).
495 - alpha < 0
496 The alpha values returned by renderImage() are not changed.
497
498 The default alpha value is -1.
499
500 \sa alpha()
501*/
502void QwtPlotRasterItem::setAlpha( int alpha )
503{
504 if ( alpha < 0 )
505 alpha = -1;
506
507 if ( alpha > 255 )
508 alpha = 255;
509
510 if ( alpha != d_data->alpha )
511 {
512 d_data->alpha = alpha;
513
514 itemChanged();
515 }
516}
517
518/*!
519 \return Alpha value of the raster item
520 \sa setAlpha()
521*/
522int QwtPlotRasterItem::alpha() const
523{
524 return d_data->alpha;
525}
526
527/*!
528 Change the cache policy
529
530 The default policy is NoCache
531
532 \param policy Cache policy
533 \sa CachePolicy, cachePolicy()
534*/
535void QwtPlotRasterItem::setCachePolicy(
536 QwtPlotRasterItem::CachePolicy policy )
537{
538 if ( d_data->cache.policy != policy )
539 {
540 d_data->cache.policy = policy;
541
542 invalidateCache();
543 itemChanged();
544 }
545}
546
547/*!
548 \return Cache policy
549 \sa CachePolicy, setCachePolicy()
550*/
551QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const
552{
553 return d_data->cache.policy;
554}
555
556/*!
557 Invalidate the paint cache
558 \sa setCachePolicy()
559*/
560void QwtPlotRasterItem::invalidateCache()
561{
562 d_data->cache.image = QImage();
563 d_data->cache.area = QRect();
564 d_data->cache.size = QSize();
565}
566
567/*!
568 \brief Pixel hint
569
570 The geometry of a pixel is used to calculated the resolution and
571 alignment of the rendered image.
572
573 Width and height of the hint need to be the horizontal
574 and vertical distances between 2 neighboured points.
575 The center of the hint has to be the position of any point
576 ( it doesn't matter which one ).
577
578 Limiting the resolution of the image might significantly improve
579 the performance and heavily reduce the amount of memory when rendering
580 a QImage from the raster data.
581
582 The default implementation returns an empty rectangle (QRectF()),
583 meaning, that the image will be rendered in target device ( f.e screen )
584 resolution.
585
586 \param area In most implementations the resolution of the data doesn't
587 depend on the requested area.
588
589 \return Bounding rectangle of a pixel
590
591 \sa render(), renderImage()
592*/
593QRectF QwtPlotRasterItem::pixelHint( const QRectF &area ) const
594{
595 Q_UNUSED( area );
596 return QRectF();
597}
598
599/*!
600 \brief Draw the raster data
601 \param painter Painter
602 \param xMap X-Scale Map
603 \param yMap Y-Scale Map
604 \param canvasRect Contents rect of the plot canvas
605*/
606void QwtPlotRasterItem::draw( QPainter *painter,
607 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
608 const QRectF &canvasRect ) const
609{
610 if ( canvasRect.isEmpty() || d_data->alpha == 0 )
611 return;
612
613 const bool doCache = useCache( d_data->cache.policy, painter );
614
615 const QwtInterval xInterval = interval( Qt::XAxis );
616 const QwtInterval yInterval = interval( Qt::YAxis );
617
618 /*
619 Scaling a rastered image always results in a loss of
620 precision/quality. So we always render the image in
621 paint device resolution.
622 */
623
624 QwtScaleMap xxMap, yyMap;
625 transformMaps( painter->transform(), xMap, yMap, xxMap, yyMap );
626
627 QRectF paintRect = painter->transform().mapRect( canvasRect );
628 QRectF area = QwtScaleMap::invTransform( xxMap, yyMap, paintRect );
629
630 const QRectF br = boundingRect();
631 if ( br.isValid() && !br.contains( area ) )
632 {
633 area &= br;
634 if ( !area.isValid() )
635 return;
636
637 paintRect = QwtScaleMap::transform( xxMap, yyMap, area );
638 }
639
640 QRectF imageRect;
641 QImage image;
642
643 QRectF pixelRect = pixelHint(area);
644 if ( !pixelRect.isEmpty() )
645 {
646 const QRectF r = QwtScaleMap::invTransform(
647 xxMap, yyMap, QRectF(0, 0, 1, 1) ).normalized();
648
649 if ( r.width() > pixelRect.width() &&
650 r.height() > pixelRect.height() )
651 {
652 /*
653 When the resolution of the data pixels is higher than
654 the resolution of the target device we render in
655 target device resolution.
656 */
657 pixelRect = QRectF();
658 }
659 }
660
661 if ( pixelRect.isEmpty() )
662 {
663 if ( QwtPainter::roundingAlignment( painter ) )
664 {
665 // we want to have maps, where the boundaries of
666 // the aligned paint rectangle exactly match the area
667
668 paintRect = qwtAlignRect(paintRect);
669 adjustMaps(xxMap, yyMap, area, paintRect);
670 }
671
672 // When we have no information about position and size of
673 // data pixels we render in resolution of the paint device.
674
675 image = compose(xxMap, yyMap,
676 area, paintRect, paintRect.size().toSize(), doCache);
677 if ( image.isNull() )
678 return;
679
680 // Remove pixels at the boundaries, when explicitly
681 // excluded in the intervals
682
683 imageRect = qwtStripRect(paintRect, area,
684 xxMap, yyMap, xInterval, yInterval);
685
686 if ( imageRect != paintRect )
687 {
688 const QRect r(
689 qRound( imageRect.x() - paintRect.x()),
690 qRound( imageRect.y() - paintRect.y() ),
691 qRound( imageRect.width() ),
692 qRound( imageRect.height() ) );
693
694 image = image.copy(r);
695 }
696 }
697 else
698 {
699 if ( QwtPainter::roundingAlignment( painter ) )
700 paintRect = qwtAlignRect(paintRect);
701
702 // align the area to the data pixels
703 QRectF imageArea = expandToPixels(area, pixelRect);
704
705 if ( imageArea.right() == xInterval.maxValue() &&
706 !( xInterval.borderFlags() & QwtInterval::ExcludeMaximum ) )
707 {
708 imageArea.adjust(0, 0, pixelRect.width(), 0);
709 }
710 if ( imageArea.bottom() == yInterval.maxValue() &&
711 !( yInterval.borderFlags() & QwtInterval::ExcludeMaximum ) )
712 {
713 imageArea.adjust(0, 0, 0, pixelRect.height() );
714 }
715
716 QSize imageSize;
717 imageSize.setWidth( qRound( imageArea.width() / pixelRect.width() ) );
718 imageSize.setHeight( qRound( imageArea.height() / pixelRect.height() ) );
719 image = compose(xxMap, yyMap,
720 imageArea, paintRect, imageSize, doCache );
721 if ( image.isNull() )
722 return;
723
724 imageRect = qwtStripRect(paintRect, area,
725 xxMap, yyMap, xInterval, yInterval);
726
727 if ( ( image.width() > 1 || image.height() > 1 ) &&
728 testPaintAttribute( PaintInDeviceResolution ) )
729 {
730 // Because of rounding errors the pixels
731 // need to be expanded manually to rectangles of
732 // different sizes
733
734 image = qwtExpandImage(image, xxMap, yyMap,
735 imageArea, area, paintRect, xInterval, yInterval );
736 }
737 }
738
739 painter->save();
740 painter->setWorldTransform( QTransform() );
741
742 QwtPainter::drawImage( painter, imageRect, image );
743
744 painter->restore();
745}
746
747/*!
748 \return Bounding interval for an axis
749
750 This method is intended to be reimplemented by derived classes.
751 The default implementation returns an invalid interval.
752
753 \param axis X, Y, or Z axis
754*/
755QwtInterval QwtPlotRasterItem::interval(Qt::Axis axis) const
756{
757 Q_UNUSED( axis );
758 return QwtInterval();
759}
760
761/*!
762 \return Bounding rect of the data
763 \sa QwtPlotRasterItem::interval()
764*/
765QRectF QwtPlotRasterItem::boundingRect() const
766{
767 const QwtInterval intervalX = interval( Qt::XAxis );
768 const QwtInterval intervalY = interval( Qt::YAxis );
769
770 if ( !intervalX.isValid() && !intervalY.isValid() )
771 return QRectF(); // no bounding rect
772
773 QRectF r;
774
775 if ( intervalX.isValid() )
776 {
777 r.setLeft( intervalX.minValue() );
778 r.setRight( intervalX.maxValue() );
779 }
780 else
781 {
782 r.setLeft(-0.5 * FLT_MAX);
783 r.setWidth(FLT_MAX);
784 }
785
786 if ( intervalY.isValid() )
787 {
788 r.setTop( intervalY.minValue() );
789 r.setBottom( intervalY.maxValue() );
790 }
791 else
792 {
793 r.setTop(-0.5 * FLT_MAX);
794 r.setHeight(FLT_MAX);
795 }
796
797 return r.normalized();
798}
799
800QImage QwtPlotRasterItem::compose(
801 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
802 const QRectF &imageArea, const QRectF &paintRect,
803 const QSize &imageSize, bool doCache) const
804{
805 QImage image;
806 if ( imageArea.isEmpty() || paintRect.isEmpty() || imageSize.isEmpty() )
807 return image;
808
809 if ( doCache )
810 {
811 if ( !d_data->cache.image.isNull()
812 && d_data->cache.area == imageArea
813 && d_data->cache.size == paintRect.size() )
814 {
815 image = d_data->cache.image;
816 }
817 }
818
819 if ( image.isNull() )
820 {
821 double dx = 0.0;
822 if ( paintRect.toRect().width() > imageSize.width() )
823 dx = imageArea.width() / imageSize.width();
824
825 const QwtScaleMap xxMap =
826 imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx);
827
828 double dy = 0.0;
829 if ( paintRect.toRect().height() > imageSize.height() )
830 dy = imageArea.height() / imageSize.height();
831
832 const QwtScaleMap yyMap =
833 imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy);
834
835 image = renderImage( xxMap, yyMap, imageArea, imageSize );
836
837 if ( doCache )
838 {
839 d_data->cache.area = imageArea;
840 d_data->cache.size = paintRect.size();
841 d_data->cache.image = image;
842 }
843 }
844
845 if ( d_data->alpha >= 0 && d_data->alpha < 255 )
846 image = toRgba( image, d_data->alpha );
847
848 return image;
849}
850
851/*!
852 \brief Calculate a scale map for painting to an image
853
854 \param orientation Orientation, Qt::Horizontal means a X axis
855 \param map Scale map for rendering the plot item
856 \param area Area to be painted on the image
857 \param imageSize Image size
858 \param pixelSize Width/Height of a data pixel
859*/
860QwtScaleMap QwtPlotRasterItem::imageMap(
861 Qt::Orientation orientation,
862 const QwtScaleMap &map, const QRectF &area,
863 const QSize &imageSize, double pixelSize) const
864{
865 double p1, p2, s1, s2;
866
867 if ( orientation == Qt::Horizontal )
868 {
869 p1 = 0.0;
870 p2 = imageSize.width();
871 s1 = area.left();
872 s2 = area.right();
873 }
874 else
875 {
876 p1 = 0.0;
877 p2 = imageSize.height();
878 s1 = area.top();
879 s2 = area.bottom();
880 }
881
882 if ( pixelSize > 0.0 )
883 {
884 double off = 0.5 * pixelSize;
885 if ( map.isInverting() )
886 off = -off;
887
888 s1 += off;
889 s2 += off;
890 }
891 else
892 {
893 p2--;
894 }
895
896 if ( map.isInverting() && ( s1 < s2 ) )
897 qSwap( s1, s2 );
898
899 QwtScaleMap newMap = map;
900 newMap.setPaintInterval( p1, p2 );
901 newMap.setScaleInterval( s1, s2 );
902
903 return newMap;
904}
Note: See TracBrowser for help on using the repository browser.