| 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 | 
 | 
|---|
| 21 | class QwtPlotRasterItem::PrivateData
 | 
|---|
| 22 | {
 | 
|---|
| 23 | public:
 | 
|---|
| 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 | 
 | 
|---|
| 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 )
 | 
|---|
| 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
 | 
|---|
| 426 | QwtPlotRasterItem::QwtPlotRasterItem( const QString& title ):
 | 
|---|
| 427 |     QwtPlotItem( QwtText( title ) )
 | 
|---|
| 428 | {
 | 
|---|
| 429 |     init();
 | 
|---|
| 430 | }
 | 
|---|
| 431 | 
 | 
|---|
| 432 | //! Constructor
 | 
|---|
| 433 | QwtPlotRasterItem::QwtPlotRasterItem( const QwtText& title ):
 | 
|---|
| 434 |     QwtPlotItem( title )
 | 
|---|
| 435 | {
 | 
|---|
| 436 |     init();
 | 
|---|
| 437 | }
 | 
|---|
| 438 | 
 | 
|---|
| 439 | //! Destructor
 | 
|---|
| 440 | QwtPlotRasterItem::~QwtPlotRasterItem()
 | 
|---|
| 441 | {
 | 
|---|
| 442 |     delete d_data;
 | 
|---|
| 443 | }
 | 
|---|
| 444 | 
 | 
|---|
| 445 | void 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 | */
 | 
|---|
| 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 );
 | 
|---|
| 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 | */
 | 
|---|
| 502 | void 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 | */
 | 
|---|
| 522 | int 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 | */
 | 
|---|
| 535 | void 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 | */
 | 
|---|
| 551 | QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const
 | 
|---|
| 552 | {
 | 
|---|
| 553 |     return d_data->cache.policy;
 | 
|---|
| 554 | }
 | 
|---|
| 555 | 
 | 
|---|
| 556 | /*!
 | 
|---|
| 557 |    Invalidate the paint cache
 | 
|---|
| 558 |    \sa setCachePolicy()
 | 
|---|
| 559 | */
 | 
|---|
| 560 | void 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 | */
 | 
|---|
| 593 | QRectF 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 | */
 | 
|---|
| 606 | void 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 | */
 | 
|---|
| 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;
 | 
|---|
| 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 | */
 | 
|---|
| 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;
 | 
|---|
| 904 | }
 | 
|---|