00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_plot_intervalcurve.h"
00011 #include "qwt_interval_symbol.h"
00012 #include "qwt_scale_map.h"
00013 #include "qwt_clipper.h"
00014 #include "qwt_painter.h"
00015 #include <string.h>
00016
00017 #include <qpainter.h>
00018
00019 static inline bool qwtIsHSampleInside( const QwtIntervalSample &sample,
00020 double xMin, double xMax, double yMin, double yMax )
00021 {
00022 const double y = sample.value;
00023 const double x1 = sample.interval.minValue();
00024 const double x2 = sample.interval.maxValue();
00025
00026 const bool isOffScreen = ( y < yMin ) || ( y > yMax )
00027 || ( x1 < xMin && x2 < xMin ) || ( x1 > xMax && x2 > xMax );
00028
00029 return !isOffScreen;
00030 }
00031
00032 static inline bool qwtIsVSampleInside( const QwtIntervalSample &sample,
00033 double xMin, double xMax, double yMin, double yMax )
00034 {
00035 const double x = sample.value;
00036 const double y1 = sample.interval.minValue();
00037 const double y2 = sample.interval.maxValue();
00038
00039 const bool isOffScreen = ( x < xMin ) || ( x > xMax )
00040 || ( y1 < yMin && y2 < yMin ) || ( y1 > yMax && y2 > yMax );
00041
00042 return !isOffScreen;
00043 }
00044
00045 class QwtPlotIntervalCurve::PrivateData
00046 {
00047 public:
00048 PrivateData():
00049 style( QwtPlotIntervalCurve::Tube ),
00050 symbol( NULL ),
00051 pen( Qt::black ),
00052 brush( Qt::white )
00053 {
00054 paintAttributes = QwtPlotIntervalCurve::ClipPolygons;
00055 paintAttributes |= QwtPlotIntervalCurve::ClipSymbol;
00056
00057 pen.setCapStyle( Qt::FlatCap );
00058 }
00059
00060 ~PrivateData()
00061 {
00062 delete symbol;
00063 }
00064
00065 QwtPlotIntervalCurve::CurveStyle style;
00066 const QwtIntervalSymbol *symbol;
00067
00068 QPen pen;
00069 QBrush brush;
00070
00071 QwtPlotIntervalCurve::PaintAttributes paintAttributes;
00072 };
00073
00078 QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QwtText &title ):
00079 QwtPlotSeriesItem( title )
00080 {
00081 init();
00082 }
00083
00088 QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QString &title ):
00089 QwtPlotSeriesItem( QwtText( title ) )
00090 {
00091 init();
00092 }
00093
00095 QwtPlotIntervalCurve::~QwtPlotIntervalCurve()
00096 {
00097 delete d_data;
00098 }
00099
00101 void QwtPlotIntervalCurve::init()
00102 {
00103 setItemAttribute( QwtPlotItem::Legend, true );
00104 setItemAttribute( QwtPlotItem::AutoScale, true );
00105
00106 d_data = new PrivateData;
00107 setData( new QwtIntervalSeriesData() );
00108
00109 setZ( 19.0 );
00110 }
00111
00113 int QwtPlotIntervalCurve::rtti() const
00114 {
00115 return QwtPlotIntervalCurve::Rtti_PlotIntervalCurve;
00116 }
00117
00125 void QwtPlotIntervalCurve::setPaintAttribute(
00126 PaintAttribute attribute, bool on )
00127 {
00128 if ( on )
00129 d_data->paintAttributes |= attribute;
00130 else
00131 d_data->paintAttributes &= ~attribute;
00132 }
00133
00138 bool QwtPlotIntervalCurve::testPaintAttribute(
00139 PaintAttribute attribute ) const
00140 {
00141 return ( d_data->paintAttributes & attribute );
00142 }
00143
00148 void QwtPlotIntervalCurve::setSamples(
00149 const QVector<QwtIntervalSample> &samples )
00150 {
00151 setData( new QwtIntervalSeriesData( samples ) );
00152 }
00153
00164 void QwtPlotIntervalCurve::setSamples(
00165 QwtSeriesData<QwtIntervalSample> *data )
00166 {
00167 setData( data );
00168 }
00169
00176 void QwtPlotIntervalCurve::setStyle( CurveStyle style )
00177 {
00178 if ( style != d_data->style )
00179 {
00180 d_data->style = style;
00181
00182 legendChanged();
00183 itemChanged();
00184 }
00185 }
00186
00191 QwtPlotIntervalCurve::CurveStyle QwtPlotIntervalCurve::style() const
00192 {
00193 return d_data->style;
00194 }
00195
00202 void QwtPlotIntervalCurve::setSymbol( const QwtIntervalSymbol *symbol )
00203 {
00204 if ( symbol != d_data->symbol )
00205 {
00206 delete d_data->symbol;
00207 d_data->symbol = symbol;
00208
00209 legendChanged();
00210 itemChanged();
00211 }
00212 }
00213
00218 const QwtIntervalSymbol *QwtPlotIntervalCurve::symbol() const
00219 {
00220 return d_data->symbol;
00221 }
00222
00236 void QwtPlotIntervalCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style )
00237 {
00238 setPen( QPen( color, width, style ) );
00239 }
00240
00246 void QwtPlotIntervalCurve::setPen( const QPen &pen )
00247 {
00248 if ( pen != d_data->pen )
00249 {
00250 d_data->pen = pen;
00251
00252 legendChanged();
00253 itemChanged();
00254 }
00255 }
00256
00261 const QPen& QwtPlotIntervalCurve::pen() const
00262 {
00263 return d_data->pen;
00264 }
00265
00274 void QwtPlotIntervalCurve::setBrush( const QBrush &brush )
00275 {
00276 if ( brush != d_data->brush )
00277 {
00278 d_data->brush = brush;
00279
00280 legendChanged();
00281 itemChanged();
00282 }
00283 }
00284
00289 const QBrush& QwtPlotIntervalCurve::brush() const
00290 {
00291 return d_data->brush;
00292 }
00293
00298 QRectF QwtPlotIntervalCurve::boundingRect() const
00299 {
00300 QRectF rect = QwtPlotSeriesItem::boundingRect();
00301 if ( rect.isValid() && orientation() == Qt::Vertical )
00302 rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
00303
00304 return rect;
00305 }
00306
00320 void QwtPlotIntervalCurve::drawSeries( QPainter *painter,
00321 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00322 const QRectF &canvasRect, int from, int to ) const
00323 {
00324 if ( to < 0 )
00325 to = dataSize() - 1;
00326
00327 if ( from < 0 )
00328 from = 0;
00329
00330 if ( from > to )
00331 return;
00332
00333 switch ( d_data->style )
00334 {
00335 case Tube:
00336 drawTube( painter, xMap, yMap, canvasRect, from, to );
00337 break;
00338
00339 case NoCurve:
00340 default:
00341 break;
00342 }
00343
00344 if ( d_data->symbol &&
00345 ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
00346 {
00347 drawSymbols( painter, *d_data->symbol,
00348 xMap, yMap, canvasRect, from, to );
00349 }
00350 }
00351
00369 void QwtPlotIntervalCurve::drawTube( QPainter *painter,
00370 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00371 const QRectF &canvasRect, int from, int to ) const
00372 {
00373 const bool doAlign = QwtPainter::roundingAlignment( painter );
00374
00375 painter->save();
00376
00377 const size_t size = to - from + 1;
00378 QPolygonF polygon( 2 * size );
00379 QPointF *points = polygon.data();
00380
00381 for ( uint i = 0; i < size; i++ )
00382 {
00383 QPointF &minValue = points[i];
00384 QPointF &maxValue = points[2 * size - 1 - i];
00385
00386 const QwtIntervalSample intervalSample = sample( from + i );
00387 if ( orientation() == Qt::Vertical )
00388 {
00389 double x = xMap.transform( intervalSample.value );
00390 double y1 = yMap.transform( intervalSample.interval.minValue() );
00391 double y2 = yMap.transform( intervalSample.interval.maxValue() );
00392 if ( doAlign )
00393 {
00394 x = qRound( x );
00395 y1 = qRound( y1 );
00396 y2 = qRound( y2 );
00397 }
00398
00399 minValue.rx() = x;
00400 minValue.ry() = y1;
00401 maxValue.rx() = x;
00402 maxValue.ry() = y2;
00403 }
00404 else
00405 {
00406 double y = yMap.transform( intervalSample.value );
00407 double x1 = xMap.transform( intervalSample.interval.minValue() );
00408 double x2 = xMap.transform( intervalSample.interval.maxValue() );
00409 if ( doAlign )
00410 {
00411 y = qRound( y );
00412 x1 = qRound( x1 );
00413 x2 = qRound( x2 );
00414 }
00415
00416 minValue.rx() = x1;
00417 minValue.ry() = y;
00418 maxValue.rx() = x2;
00419 maxValue.ry() = y;
00420 }
00421 }
00422
00423 if ( d_data->brush.style() != Qt::NoBrush )
00424 {
00425 painter->setPen( QPen( Qt::NoPen ) );
00426 painter->setBrush( d_data->brush );
00427
00428 if ( d_data->paintAttributes & ClipPolygons )
00429 {
00430 const qreal m = 1.0;
00431 const QPolygonF p = QwtClipper::clipPolygonF(
00432 canvasRect.adjusted( -m, -m, m, m ), polygon, true );
00433
00434 QwtPainter::drawPolygon( painter, p );
00435 }
00436 else
00437 {
00438 QwtPainter::drawPolygon( painter, polygon );
00439 }
00440 }
00441
00442 if ( d_data->pen.style() != Qt::NoPen )
00443 {
00444 painter->setPen( d_data->pen );
00445 painter->setBrush( Qt::NoBrush );
00446
00447 if ( d_data->paintAttributes & ClipPolygons )
00448 {
00449 qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF() );
00450 const QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw );
00451
00452 QPolygonF p;
00453
00454 p.resize( size );
00455 ::memcpy( p.data(), points, size * sizeof( QPointF ) );
00456 p = QwtClipper::clipPolygonF( clipRect, p );
00457 QwtPainter::drawPolyline( painter, p );
00458
00459 p.resize( size );
00460 ::memcpy( p.data(), points + size, size * sizeof( QPointF ) );
00461 p = QwtClipper::clipPolygonF( clipRect, p );
00462 QwtPainter::drawPolyline( painter, p );
00463 }
00464 else
00465 {
00466 QwtPainter::drawPolyline( painter, points, size );
00467 QwtPainter::drawPolyline( painter, points + size, size );
00468 }
00469 }
00470
00471 painter->restore();
00472 }
00473
00487 void QwtPlotIntervalCurve::drawSymbols(
00488 QPainter *painter, const QwtIntervalSymbol &symbol,
00489 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00490 const QRectF &canvasRect, int from, int to ) const
00491 {
00492 painter->save();
00493
00494 QPen pen = symbol.pen();
00495 pen.setCapStyle( Qt::FlatCap );
00496
00497 painter->setPen( pen );
00498 painter->setBrush( symbol.brush() );
00499
00500 const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
00501
00502 const double xMin = tr.left();
00503 const double xMax = tr.right();
00504 const double yMin = tr.top();
00505 const double yMax = tr.bottom();
00506
00507 const bool doClip = d_data->paintAttributes & ClipSymbol;
00508
00509 for ( int i = from; i <= to; i++ )
00510 {
00511 const QwtIntervalSample s = sample( i );
00512
00513 if ( orientation() == Qt::Vertical )
00514 {
00515 if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) )
00516 {
00517 const double x = xMap.transform( s.value );
00518 const double y1 = yMap.transform( s.interval.minValue() );
00519 const double y2 = yMap.transform( s.interval.maxValue() );
00520
00521 symbol.draw( painter, orientation(),
00522 QPointF( x, y1 ), QPointF( x, y2 ) );
00523 }
00524 }
00525 else
00526 {
00527 if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) )
00528 {
00529 const double y = yMap.transform( s.value );
00530 const double x1 = xMap.transform( s.interval.minValue() );
00531 const double x2 = xMap.transform( s.interval.maxValue() );
00532
00533 symbol.draw( painter, orientation(),
00534 QPointF( x1, y ), QPointF( x2, y ) );
00535 }
00536 }
00537 }
00538
00539 painter->restore();
00540 }
00541
00554 QwtGraphic QwtPlotIntervalCurve::legendIcon(
00555 int index, const QSizeF &size ) const
00556 {
00557 Q_UNUSED( index );
00558
00559 if ( size.isEmpty() )
00560 return QwtGraphic();
00561
00562 QwtGraphic icon;
00563 icon.setDefaultSize( size );
00564 icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
00565
00566 QPainter painter( &icon );
00567 painter.setRenderHint( QPainter::Antialiasing,
00568 testRenderHint( QwtPlotItem::RenderAntialiased ) );
00569
00570 if ( d_data->style == Tube )
00571 {
00572 QRectF r( 0, 0, size.width(), size.height() );
00573 painter.fillRect( r, d_data->brush );
00574 }
00575
00576 if ( d_data->symbol &&
00577 ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
00578 {
00579 QPen pen = d_data->symbol->pen();
00580 pen.setWidthF( pen.widthF() );
00581 pen.setCapStyle( Qt::FlatCap );
00582
00583 painter.setPen( pen );
00584 painter.setBrush( d_data->symbol->brush() );
00585
00586 if ( orientation() == Qt::Vertical )
00587 {
00588 const double x = 0.5 * size.width();
00589
00590 d_data->symbol->draw( &painter, orientation(),
00591 QPointF( x, 0 ), QPointF( x, size.height() - 1.0 ) );
00592 }
00593 else
00594 {
00595 const double y = 0.5 * size.height();
00596
00597 d_data->symbol->draw( &painter, orientation(),
00598 QPointF( 0.0, y ), QPointF( size.width() - 1.0, y ) );
00599 }
00600 }
00601
00602 return icon;
00603 }