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::clippedPolygonF(
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( size );
00453
00454 ::memcpy( p.data(), points, size * sizeof( QPointF ) );
00455 QwtPainter::drawPolyline( painter,
00456 QwtClipper::clippedPolygonF( clipRect, p ) );
00457
00458 ::memcpy( p.data(), points + size, size * sizeof( QPointF ) );
00459 QwtPainter::drawPolyline( painter,
00460 QwtClipper::clippedPolygonF( clipRect, p ) );
00461 }
00462 else
00463 {
00464 QwtPainter::drawPolyline( painter, points, size );
00465 QwtPainter::drawPolyline( painter, points + size, size );
00466 }
00467 }
00468
00469 painter->restore();
00470 }
00471
00485 void QwtPlotIntervalCurve::drawSymbols(
00486 QPainter *painter, const QwtIntervalSymbol &symbol,
00487 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00488 const QRectF &canvasRect, int from, int to ) const
00489 {
00490 painter->save();
00491
00492 QPen pen = symbol.pen();
00493 pen.setCapStyle( Qt::FlatCap );
00494
00495 painter->setPen( pen );
00496 painter->setBrush( symbol.brush() );
00497
00498 const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
00499
00500 const double xMin = tr.left();
00501 const double xMax = tr.right();
00502 const double yMin = tr.top();
00503 const double yMax = tr.bottom();
00504
00505 const bool doClip = d_data->paintAttributes & ClipSymbol;
00506
00507 for ( int i = from; i <= to; i++ )
00508 {
00509 const QwtIntervalSample s = sample( i );
00510
00511 if ( orientation() == Qt::Vertical )
00512 {
00513 if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) )
00514 {
00515 const double x = xMap.transform( s.value );
00516 const double y1 = yMap.transform( s.interval.minValue() );
00517 const double y2 = yMap.transform( s.interval.maxValue() );
00518
00519 symbol.draw( painter, orientation(),
00520 QPointF( x, y1 ), QPointF( x, y2 ) );
00521 }
00522 }
00523 else
00524 {
00525 if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) )
00526 {
00527 const double y = yMap.transform( s.value );
00528 const double x1 = xMap.transform( s.interval.minValue() );
00529 const double x2 = xMap.transform( s.interval.maxValue() );
00530
00531 symbol.draw( painter, orientation(),
00532 QPointF( x1, y ), QPointF( x2, y ) );
00533 }
00534 }
00535 }
00536
00537 painter->restore();
00538 }
00539
00552 QwtGraphic QwtPlotIntervalCurve::legendIcon(
00553 int index, const QSizeF &size ) const
00554 {
00555 Q_UNUSED( index );
00556
00557 if ( size.isEmpty() )
00558 return QwtGraphic();
00559
00560 QwtGraphic icon;
00561 icon.setDefaultSize( size );
00562 icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
00563
00564 QPainter painter( &icon );
00565 painter.setRenderHint( QPainter::Antialiasing,
00566 testRenderHint( QwtPlotItem::RenderAntialiased ) );
00567
00568 if ( d_data->style == Tube )
00569 {
00570 QRectF r( 0, 0, size.width(), size.height() );
00571 painter.fillRect( r, d_data->brush );
00572 }
00573
00574 if ( d_data->symbol &&
00575 ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
00576 {
00577 QPen pen = d_data->symbol->pen();
00578 pen.setWidthF( pen.widthF() );
00579 pen.setCapStyle( Qt::FlatCap );
00580
00581 painter.setPen( pen );
00582 painter.setBrush( d_data->symbol->brush() );
00583
00584 if ( orientation() == Qt::Vertical )
00585 {
00586 const double x = 0.5 * size.width();
00587
00588 d_data->symbol->draw( &painter, orientation(),
00589 QPointF( x, 0 ), QPointF( x, size.height() - 1.0 ) );
00590 }
00591 else
00592 {
00593 const double y = 0.5 * size.height();
00594
00595 d_data->symbol->draw( &painter, orientation(),
00596 QPointF( 0.0, y ), QPointF( size.width() - 1.0, y ) );
00597 }
00598 }
00599
00600 return icon;
00601 }