~ubuntu-branches/ubuntu/saucy/goldencheetah/saucy

« back to all changes in this revision

Viewing changes to qwt/src/qwt_plot_rasteritem.cpp

  • Committer: Package Import Robot
  • Author(s): KURASHIKI Satoru
  • Date: 2013-08-18 07:02:45 UTC
  • mfrom: (4.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20130818070245-zgdvb47e1k3mtgil
Tags: 3.0-3
debian/control: remove needless dependency. (Closes: #719571)

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
 * modify it under the terms of the Qwt License, Version 1.0
8
8
 *****************************************************************************/
9
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"
10
15
#include <qapplication.h>
11
16
#include <qdesktopwidget.h>
12
 
#include <qpaintdevice.h>
13
17
#include <qpainter.h>
14
 
#include "qwt_legend.h"
15
 
#include "qwt_legend_item.h"
16
 
#include "qwt_scale_map.h"
17
 
#include "qwt_plot_rasteritem.h"
 
18
#include <qpaintengine.h>
 
19
#include <float.h>
18
20
 
19
21
class QwtPlotRasterItem::PrivateData
20
22
{
21
23
public:
22
24
    PrivateData():
23
 
        alpha(-1)
 
25
        alpha( -1 ),
 
26
        paintAttributes( QwtPlotRasterItem::PaintInDeviceResolution )
24
27
    {
25
28
        cache.policy = QwtPlotRasterItem::NoCache;
26
29
    }
27
30
 
28
31
    int alpha;
 
32
    QwtPlotRasterItem::PaintAttributes paintAttributes;
29
33
 
30
34
    struct ImageCache
31
35
    {
32
36
        QwtPlotRasterItem::CachePolicy policy;
33
 
        QwtDoubleRect rect;
34
 
        QSize size;
 
37
        QRectF area;
 
38
        QSizeF size;
35
39
        QImage image;
36
40
    } cache;
37
41
};
38
42
 
39
 
static QImage toRgba(const QImage& image, int alpha)
40
 
{
41
 
    if ( alpha < 0 || alpha >= 255 )  
 
43
 
 
44
static 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
 
 
55
static 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
 
 
107
static 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
 
 
299
static 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
 
 
318
static 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
 
 
332
static 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
 
 
353
static 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
 
 
379
static QImage toRgba( const QImage& image, int alpha )
 
380
{
 
381
    if ( alpha < 0 || alpha >= 255 )
42
382
        return image;
43
383
 
44
 
#if QT_VERSION < 0x040000
45
 
    QImage alphaImage(image.size(), 32);
46
 
    alphaImage.setAlphaBuffer(true);
47
 
#else
48
 
    QImage alphaImage(image.size(), QImage::Format_ARGB32);
49
 
#endif
 
384
    QImage alphaImage( image.size(), QImage::Format_ARGB32 );
50
385
 
51
 
    const QRgb mask1 = qRgba(0, 0, 0, alpha);
52
 
    const QRgb mask2 = qRgba(255, 255, 255, 0);
53
 
    const QRgb mask3 = qRgba(0, 0, 0, 255);
 
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 );
54
389
 
55
390
    const int w = image.size().width();
56
391
    const int h = image.size().height();
59
394
    {
60
395
        for ( int y = 0; y < h; y++ )
61
396
        {
62
 
            QRgb* alphaLine = (QRgb*)alphaImage.scanLine(y);
63
 
            const unsigned char *line = image.scanLine(y);
 
397
            QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y );
 
398
            const unsigned char *line = image.scanLine( y );
64
399
 
65
400
            for ( int x = 0; x < w; x++ )
66
 
                *alphaLine++ = (image.color(*line++) & mask2) | mask1;
 
401
                *alphaLine++ = ( image.color( *line++ ) & mask2 ) | mask1;
67
402
        }
68
403
    }
69
404
    else if ( image.depth() == 32 )
70
405
    {
71
406
        for ( int y = 0; y < h; y++ )
72
407
        {
73
 
            QRgb* alphaLine = (QRgb*)alphaImage.scanLine(y);
74
 
            const QRgb* line = (const QRgb*) image.scanLine(y);
 
408
            QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y );
 
409
            const QRgb* line = ( const QRgb* ) image.scanLine( y );
75
410
 
76
411
            for ( int x = 0; x < w; x++ )
77
412
            {
78
413
                const QRgb rgb = *line++;
79
414
                if ( rgb & mask3 ) // alpha != 0
80
 
                    *alphaLine++ = (rgb & mask2) | mask1;
 
415
                    *alphaLine++ = ( rgb & mask2 ) | mask1;
81
416
                else
82
417
                    *alphaLine++ = rgb;
83
418
            }
88
423
}
89
424
 
90
425
//! Constructor
91
 
QwtPlotRasterItem::QwtPlotRasterItem(const QString& title):
92
 
    QwtPlotItem(QwtText(title))
 
426
QwtPlotRasterItem::QwtPlotRasterItem( const QString& title ):
 
427
    QwtPlotItem( QwtText( title ) )
93
428
{
94
429
    init();
95
430
}
96
431
 
97
432
//! Constructor
98
 
QwtPlotRasterItem::QwtPlotRasterItem(const QwtText& title):
99
 
    QwtPlotItem(title)
 
433
QwtPlotRasterItem::QwtPlotRasterItem( const QwtText& title ):
 
434
    QwtPlotItem( title )
100
435
{
101
436
    init();
102
437
}
111
446
{
112
447
    d_data = new PrivateData();
113
448
 
114
 
    setItemAttribute(QwtPlotItem::AutoScale, true);
115
 
    setItemAttribute(QwtPlotItem::Legend, false);
116
 
 
117
 
    setZ(8.0);
 
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
*/
 
462
void 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
*/
 
474
bool QwtPlotRasterItem::testPaintAttribute( PaintAttribute attribute ) const
 
475
{
 
476
    return ( d_data->paintAttributes & attribute );
118
477
}
119
478
 
120
479
/*!
125
484
   Using setAlpha() raster items can be stacked easily.
126
485
 
127
486
   The alpha value is a value [0, 255] to
128
 
   control the transparency of the image. 0 represents a fully 
 
487
   control the transparency of the image. 0 represents a fully
129
488
   transparent color, while 255 represents a fully opaque color.
130
 
   
 
489
 
131
490
   \param alpha Alpha value
132
491
 
133
492
   - alpha >= 0\n
134
 
     All alpha values of the pixels returned by renderImage() will be set to 
135
 
     alpha, beside those with an alpha value of 0 (invalid pixels). 
 
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).
136
495
   - alpha < 0
137
496
     The alpha values returned by renderImage() are not changed.
138
497
 
140
499
 
141
500
   \sa alpha()
142
501
*/
143
 
void QwtPlotRasterItem::setAlpha(int alpha)
 
502
void QwtPlotRasterItem::setAlpha( int alpha )
144
503
{
145
504
    if ( alpha < 0 )
146
505
        alpha = -1;
174
533
  \sa CachePolicy, cachePolicy()
175
534
*/
176
535
void QwtPlotRasterItem::setCachePolicy(
177
 
    QwtPlotRasterItem::CachePolicy policy)
 
536
    QwtPlotRasterItem::CachePolicy policy )
178
537
{
179
538
    if ( d_data->cache.policy != policy )
180
539
    {
201
560
void QwtPlotRasterItem::invalidateCache()
202
561
{
203
562
    d_data->cache.image = QImage();
204
 
    d_data->cache.rect = QwtDoubleRect();
 
563
    d_data->cache.area = QRect();
205
564
    d_data->cache.size = QSize();
206
565
}
207
566
 
208
567
/*!
209
 
   \brief Returns the recommended raster for a given rect.
210
 
 
211
 
   F.e the raster hint can be used to limit the resolution of
212
 
   the image that is rendered.
213
 
 
214
 
   The default implementation returns an invalid size (QSize()),
215
 
   what means: no hint.
 
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()
216
592
*/
217
 
QSize QwtPlotRasterItem::rasterHint(const QwtDoubleRect &) const
 
593
QRectF QwtPlotRasterItem::pixelHint( const QRectF &area ) const
218
594
{
219
 
    return QSize();
 
595
    Q_UNUSED( area );
 
596
    return QRectF();
220
597
}
221
598
 
222
599
/*!
226
603
  \param yMap Y-Scale Map
227
604
  \param canvasRect Contents rect of the plot canvas
228
605
*/
229
 
void QwtPlotRasterItem::draw(QPainter *painter,
 
606
void QwtPlotRasterItem::draw( QPainter *painter,
230
607
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
231
 
    const QRect &canvasRect) const
 
608
    const QRectF &canvasRect ) const
232
609
{
233
610
    if ( canvasRect.isEmpty() || d_data->alpha == 0 )
234
611
        return;
235
612
 
236
 
    QwtDoubleRect area = invTransform(xMap, yMap, canvasRect);
237
 
    if ( boundingRect().isValid() )
238
 
        area &= boundingRect();
239
 
 
240
 
    const QRect paintRect = transform(xMap, yMap, area);
241
 
    if ( !paintRect.isValid() )
242
 
        return;
243
 
 
244
 
    QImage image;
245
 
 
246
 
    bool doCache = true;
247
 
    if ( painter->device()->devType() == QInternal::Printer 
248
 
            || painter->device()->devType() == QInternal::Picture )
249
 
    {
250
 
        doCache = false;
251
 
    }
252
 
 
253
 
    if ( !doCache || d_data->cache.policy == NoCache )
254
 
    {
255
 
        image = renderImage(xMap, yMap, area);
256
 
        if ( d_data->alpha >= 0 && d_data->alpha < 255 )
257
 
            image = toRgba(image, d_data->alpha);
258
 
 
259
 
    }
260
 
    else if ( d_data->cache.policy == PaintCache )
261
 
    {
262
 
        if ( d_data->cache.image.isNull() || d_data->cache.rect != area
263
 
            || d_data->cache.size != paintRect.size() )
264
 
        {
265
 
            d_data->cache.image = renderImage(xMap, yMap, area);
266
 
            d_data->cache.rect = area;
 
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
*/
 
755
QwtInterval 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
*/
 
765
QRectF 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
 
 
800
QImage 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;
267
840
            d_data->cache.size = paintRect.size();
268
 
        }
269
 
 
270
 
        image = d_data->cache.image;
271
 
        if ( d_data->alpha >= 0 && d_data->alpha < 255 )
272
 
            image = toRgba(image, d_data->alpha);
273
 
    }
274
 
    else if ( d_data->cache.policy == ScreenCache )
275
 
    {
276
 
        const QSize screenSize =
277
 
            QApplication::desktop()->screenGeometry().size();
278
 
 
279
 
        if ( paintRect.width() > screenSize.width() ||
280
 
            paintRect.height() > screenSize.height() )
281
 
        {
282
 
            image = renderImage(xMap, yMap, area);
283
 
        }
284
 
        else
285
 
        {
286
 
            if ( d_data->cache.image.isNull() || d_data->cache.rect != area )
287
 
            {
288
 
                QwtScaleMap cacheXMap = xMap;
289
 
                cacheXMap.setPaintInterval( 0, screenSize.width());
290
 
 
291
 
                QwtScaleMap cacheYMap = yMap;
292
 
                cacheYMap.setPaintInterval(screenSize.height(), 0);
293
 
 
294
 
                d_data->cache.image = renderImage(
295
 
                    cacheXMap, cacheYMap, area);
296
 
                d_data->cache.rect = area;
297
 
                d_data->cache.size = paintRect.size();
298
 
            }
299
 
 
300
 
            image = d_data->cache.image;
301
 
        }
302
 
        image = toRgba(image, d_data->alpha);
303
 
    }
304
 
 
305
 
    painter->drawImage(paintRect, image);
 
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
*/
 
860
QwtScaleMap 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;
306
904
}