source: ntrip/trunk/GnssCenter/qwt/qwt_plot_curve.cpp@ 9448

Last change on this file since 9448 was 4839, checked in by mervart, 12 years ago
File size: 28.3 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_plot_curve.h"
11#include "qwt_math.h"
12#include "qwt_clipper.h"
13#include "qwt_painter.h"
14#include "qwt_legend.h"
15#include "qwt_legend_item.h"
16#include "qwt_scale_map.h"
17#include "qwt_plot.h"
18#include "qwt_plot_canvas.h"
19#include "qwt_curve_fitter.h"
20#include "qwt_symbol.h"
21#include <qpainter.h>
22#include <qpixmap.h>
23#include <qalgorithms.h>
24#include <qmath.h>
25
26static int verifyRange( int size, int &i1, int &i2 )
27{
28 if ( size < 1 )
29 return 0;
30
31 i1 = qBound( 0, i1, size - 1 );
32 i2 = qBound( 0, i2, size - 1 );
33
34 if ( i1 > i2 )
35 qSwap( i1, i2 );
36
37 return ( i2 - i1 + 1 );
38}
39
40class QwtPlotCurve::PrivateData
41{
42public:
43 PrivateData():
44 style( QwtPlotCurve::Lines ),
45 baseline( 0.0 ),
46 symbol( NULL ),
47 attributes( 0 ),
48 paintAttributes( QwtPlotCurve::ClipPolygons ),
49 legendAttributes( 0 )
50 {
51 pen = QPen( Qt::black );
52 curveFitter = new QwtSplineCurveFitter;
53 }
54
55 ~PrivateData()
56 {
57 delete symbol;
58 delete curveFitter;
59 }
60
61 QwtPlotCurve::CurveStyle style;
62 double baseline;
63
64 const QwtSymbol *symbol;
65 QwtCurveFitter *curveFitter;
66
67 QPen pen;
68 QBrush brush;
69
70 QwtPlotCurve::CurveAttributes attributes;
71 QwtPlotCurve::PaintAttributes paintAttributes;
72
73 QwtPlotCurve::LegendAttributes legendAttributes;
74};
75
76/*!
77 Constructor
78 \param title Title of the curve
79*/
80QwtPlotCurve::QwtPlotCurve( const QwtText &title ):
81 QwtPlotSeriesItem<QPointF>( title )
82{
83 init();
84}
85
86/*!
87 Constructor
88 \param title Title of the curve
89*/
90QwtPlotCurve::QwtPlotCurve( const QString &title ):
91 QwtPlotSeriesItem<QPointF>( QwtText( title ) )
92{
93 init();
94}
95
96//! Destructor
97QwtPlotCurve::~QwtPlotCurve()
98{
99 delete d_data;
100}
101
102//! Initialize internal members
103void QwtPlotCurve::init()
104{
105 setItemAttribute( QwtPlotItem::Legend );
106 setItemAttribute( QwtPlotItem::AutoScale );
107
108 d_data = new PrivateData;
109 d_series = new QwtPointSeriesData();
110
111 setZ( 20.0 );
112}
113
114//! \return QwtPlotItem::Rtti_PlotCurve
115int QwtPlotCurve::rtti() const
116{
117 return QwtPlotItem::Rtti_PlotCurve;
118}
119
120/*!
121 Specify an attribute how to draw the curve
122
123 \param attribute Paint attribute
124 \param on On/Off
125 \sa testPaintAttribute()
126*/
127void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on )
128{
129 if ( on )
130 d_data->paintAttributes |= attribute;
131 else
132 d_data->paintAttributes &= ~attribute;
133}
134
135/*!
136 \brief Return the current paint attributes
137 \sa setPaintAttribute()
138*/
139bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const
140{
141 return ( d_data->paintAttributes & attribute );
142}
143
144/*!
145 Specify an attribute how to draw the legend identifier
146
147 \param attribute Attribute
148 \param on On/Off
149 /sa testLegendAttribute()
150*/
151void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on )
152{
153 if ( on )
154 d_data->legendAttributes |= attribute;
155 else
156 d_data->legendAttributes &= ~attribute;
157}
158
159/*!
160 \brief Return the current paint attributes
161 \sa setLegendAttribute()
162*/
163bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const
164{
165 return ( d_data->legendAttributes & attribute );
166}
167
168/*!
169 Set the curve's drawing style
170
171 \param style Curve style
172 \sa style()
173*/
174void QwtPlotCurve::setStyle( CurveStyle style )
175{
176 if ( style != d_data->style )
177 {
178 d_data->style = style;
179 itemChanged();
180 }
181}
182
183/*!
184 Return the current style
185 \sa setStyle()
186*/
187QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
188{
189 return d_data->style;
190}
191
192/*!
193 Assign a symbol
194
195 \param symbol Symbol
196 \sa symbol()
197*/
198void QwtPlotCurve::setSymbol( const QwtSymbol *symbol )
199{
200 if ( symbol != d_data->symbol )
201 {
202 delete d_data->symbol;
203 d_data->symbol = symbol;
204 itemChanged();
205 }
206}
207
208/*!
209 \return Current symbol or NULL, when no symbol has been assigned
210 \sa setSymbol()
211*/
212const QwtSymbol *QwtPlotCurve::symbol() const
213{
214 return d_data->symbol;
215}
216
217/*!
218 Assign a pen
219
220 \param pen New pen
221 \sa pen(), brush()
222*/
223void QwtPlotCurve::setPen( const QPen &pen )
224{
225 if ( pen != d_data->pen )
226 {
227 d_data->pen = pen;
228 itemChanged();
229 }
230}
231
232/*!
233 \return Pen used to draw the lines
234 \sa setPen(), brush()
235*/
236const QPen& QwtPlotCurve::pen() const
237{
238 return d_data->pen;
239}
240
241/*!
242 \brief Assign a brush.
243
244 In case of brush.style() != QBrush::NoBrush
245 and style() != QwtPlotCurve::Sticks
246 the area between the curve and the baseline will be filled.
247
248 In case !brush.color().isValid() the area will be filled by
249 pen.color(). The fill algorithm simply connects the first and the
250 last curve point to the baseline. So the curve data has to be sorted
251 (ascending or descending).
252
253 \param brush New brush
254 \sa brush(), setBaseline(), baseline()
255*/
256void QwtPlotCurve::setBrush( const QBrush &brush )
257{
258 if ( brush != d_data->brush )
259 {
260 d_data->brush = brush;
261 itemChanged();
262 }
263}
264
265/*!
266 \return Brush used to fill the area between lines and the baseline
267 \sa setBrush(), setBaseline(), baseline()
268*/
269const QBrush& QwtPlotCurve::brush() const
270{
271 return d_data->brush;
272}
273
274/*!
275 Draw an interval of the curve
276
277 \param painter Painter
278 \param xMap Maps x-values into pixel coordinates.
279 \param yMap Maps y-values into pixel coordinates.
280 \param canvasRect Contents rect of the canvas
281 \param from Index of the first point to be painted
282 \param to Index of the last point to be painted. If to < 0 the
283 curve will be painted to its last point.
284
285 \sa drawCurve(), drawSymbols(),
286*/
287void QwtPlotCurve::drawSeries( QPainter *painter,
288 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
289 const QRectF &canvasRect, int from, int to ) const
290{
291 if ( !painter || dataSize() <= 0 )
292 return;
293
294 if ( to < 0 )
295 to = dataSize() - 1;
296
297 if ( verifyRange( dataSize(), from, to ) > 0 )
298 {
299 painter->save();
300 painter->setPen( d_data->pen );
301
302 /*
303 Qt 4.0.0 is slow when drawing lines, but it's even
304 slower when the painter has a brush. So we don't
305 set the brush before we really need it.
306 */
307
308 drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to );
309 painter->restore();
310
311 if ( d_data->symbol &&
312 ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
313 {
314 painter->save();
315 drawSymbols( painter, *d_data->symbol,
316 xMap, yMap, canvasRect, from, to );
317 painter->restore();
318 }
319 }
320}
321
322/*!
323 \brief Draw the line part (without symbols) of a curve interval.
324 \param painter Painter
325 \param style curve style, see QwtPlotCurve::CurveStyle
326 \param xMap x map
327 \param yMap y map
328 \param canvasRect Contents rect of the canvas
329 \param from index of the first point to be painted
330 \param to index of the last point to be painted
331 \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks()
332*/
333void QwtPlotCurve::drawCurve( QPainter *painter, int style,
334 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
335 const QRectF &canvasRect, int from, int to ) const
336{
337 switch ( style )
338 {
339 case Lines:
340 if ( testCurveAttribute( Fitted ) )
341 {
342 // we always need the complete
343 // curve for fitting
344 from = 0;
345 to = dataSize() - 1;
346 }
347 drawLines( painter, xMap, yMap, canvasRect, from, to );
348 break;
349 case Sticks:
350 drawSticks( painter, xMap, yMap, canvasRect, from, to );
351 break;
352 case Steps:
353 drawSteps( painter, xMap, yMap, canvasRect, from, to );
354 break;
355 case Dots:
356 drawDots( painter, xMap, yMap, canvasRect, from, to );
357 break;
358 case NoCurve:
359 default:
360 break;
361 }
362}
363
364/*!
365 \brief Draw lines
366
367 If the CurveAttribute Fitted is enabled a QwtCurveFitter tries
368 to interpolate/smooth the curve, before it is painted.
369
370 \param painter Painter
371 \param xMap x map
372 \param yMap y map
373 \param canvasRect Contents rect of the canvas
374 \param from index of the first point to be painted
375 \param to index of the last point to be painted
376
377 \sa setCurveAttribute(), setCurveFitter(), draw(),
378 drawLines(), drawDots(), drawSteps(), drawSticks()
379*/
380void QwtPlotCurve::drawLines( QPainter *painter,
381 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
382 const QRectF &canvasRect, int from, int to ) const
383{
384 int size = to - from + 1;
385 if ( size <= 0 )
386 return;
387
388 const bool doAlign = QwtPainter::roundingAlignment( painter );
389
390 QPolygonF polyline( size );
391
392 QPointF *points = polyline.data();
393 for ( int i = from; i <= to; i++ )
394 {
395 const QPointF sample = d_series->sample( i );
396
397 double x = xMap.transform( sample.x() );
398 double y = yMap.transform( sample.y() );
399 if ( doAlign )
400 {
401 x = qRound( x );
402 y = qRound( y );
403 }
404
405 points[i - from].rx() = x;
406 points[i - from].ry() = y;
407 }
408
409 if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
410 polyline = d_data->curveFitter->fitCurve( polyline );
411
412 if ( d_data->paintAttributes & ClipPolygons )
413 {
414 qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
415 const QPolygonF clipped = QwtClipper::clipPolygonF(
416 canvasRect.adjusted(-pw, -pw, pw, pw), polyline, false );
417
418 QwtPainter::drawPolyline( painter, clipped );
419 }
420 else
421 {
422 QwtPainter::drawPolyline( painter, polyline );
423 }
424
425 if ( d_data->brush.style() != Qt::NoBrush )
426 fillCurve( painter, xMap, yMap, canvasRect, polyline );
427}
428
429/*!
430 Draw sticks
431
432 \param painter Painter
433 \param xMap x map
434 \param yMap y map
435 \param canvasRect Contents rect of the canvas
436 \param from index of the first point to be painted
437 \param to index of the last point to be painted
438
439 \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps()
440*/
441void QwtPlotCurve::drawSticks( QPainter *painter,
442 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
443 const QRectF &, int from, int to ) const
444{
445 painter->save();
446 painter->setRenderHint( QPainter::Antialiasing, false );
447
448 const bool doAlign = QwtPainter::roundingAlignment( painter );
449
450 double x0 = xMap.transform( d_data->baseline );
451 double y0 = yMap.transform( d_data->baseline );
452 if ( doAlign )
453 {
454 x0 = qRound( x0 );
455 y0 = qRound( y0 );
456 }
457
458 const Qt::Orientation o = orientation();
459
460 for ( int i = from; i <= to; i++ )
461 {
462 const QPointF sample = d_series->sample( i );
463 double xi = xMap.transform( sample.x() );
464 double yi = yMap.transform( sample.y() );
465 if ( doAlign )
466 {
467 xi = qRound( xi );
468 yi = qRound( yi );
469 }
470
471 if ( o == Qt::Horizontal )
472 QwtPainter::drawLine( painter, x0, yi, xi, yi );
473 else
474 QwtPainter::drawLine( painter, xi, y0, xi, yi );
475 }
476
477 painter->restore();
478}
479
480/*!
481 Draw dots
482
483 \param painter Painter
484 \param xMap x map
485 \param yMap y map
486 \param canvasRect Contents rect of the canvas
487 \param from index of the first point to be painted
488 \param to index of the last point to be painted
489
490 \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
491*/
492void QwtPlotCurve::drawDots( QPainter *painter,
493 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
494 const QRectF &canvasRect, int from, int to ) const
495{
496 const bool doFill = d_data->brush.style() != Qt::NoBrush;
497 const bool doAlign = QwtPainter::roundingAlignment( painter );
498
499 QPolygonF polyline;
500 if ( doFill )
501 polyline.resize( to - from + 1 );
502
503 QPointF *points = polyline.data();
504
505 for ( int i = from; i <= to; i++ )
506 {
507 const QPointF sample = d_series->sample( i );
508 double xi = xMap.transform( sample.x() );
509 double yi = yMap.transform( sample.y() );
510 if ( doAlign )
511 {
512 xi = qRound( xi );
513 yi = qRound( yi );
514 }
515
516 QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
517
518 if ( doFill )
519 {
520 points[i - from].rx() = xi;
521 points[i - from].ry() = yi;
522 }
523 }
524
525 if ( doFill )
526 fillCurve( painter, xMap, yMap, canvasRect, polyline );
527}
528
529/*!
530 Draw step function
531
532 The direction of the steps depends on Inverted attribute.
533
534 \param painter Painter
535 \param xMap x map
536 \param yMap y map
537 \param canvasRect Contents rect of the canvas
538 \param from index of the first point to be painted
539 \param to index of the last point to be painted
540
541 \sa CurveAttribute, setCurveAttribute(),
542 draw(), drawCurve(), drawDots(), drawLines(), drawSticks()
543*/
544void QwtPlotCurve::drawSteps( QPainter *painter,
545 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
546 const QRectF &canvasRect, int from, int to ) const
547{
548 const bool doAlign = QwtPainter::roundingAlignment( painter );
549
550 QPolygonF polygon( 2 * ( to - from ) + 1 );
551 QPointF *points = polygon.data();
552
553 bool inverted = orientation() == Qt::Vertical;
554 if ( d_data->attributes & Inverted )
555 inverted = !inverted;
556
557 int i, ip;
558 for ( i = from, ip = 0; i <= to; i++, ip += 2 )
559 {
560 const QPointF sample = d_series->sample( i );
561 double xi = xMap.transform( sample.x() );
562 double yi = yMap.transform( sample.y() );
563 if ( doAlign )
564 {
565 xi = qRound( xi );
566 yi = qRound( yi );
567 }
568
569 if ( ip > 0 )
570 {
571 const QPointF &p0 = points[ip - 2];
572 QPointF &p = points[ip - 1];
573
574 if ( inverted )
575 {
576 p.rx() = p0.x();
577 p.ry() = yi;
578 }
579 else
580 {
581 p.rx() = xi;
582 p.ry() = p0.y();
583 }
584 }
585
586 points[ip].rx() = xi;
587 points[ip].ry() = yi;
588 }
589
590 if ( d_data->paintAttributes & ClipPolygons )
591 {
592 const QPolygonF clipped = QwtClipper::clipPolygonF(
593 canvasRect, polygon, false );
594
595 QwtPainter::drawPolyline( painter, clipped );
596 }
597 else
598 {
599 QwtPainter::drawPolyline( painter, polygon );
600 }
601
602 if ( d_data->brush.style() != Qt::NoBrush )
603 fillCurve( painter, xMap, yMap, canvasRect, polygon );
604}
605
606
607/*!
608 Specify an attribute for drawing the curve
609
610 \param attribute Curve attribute
611 \param on On/Off
612
613 /sa testCurveAttribute(), setCurveFitter()
614*/
615void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on )
616{
617 if ( bool( d_data->attributes & attribute ) == on )
618 return;
619
620 if ( on )
621 d_data->attributes |= attribute;
622 else
623 d_data->attributes &= ~attribute;
624
625 itemChanged();
626}
627
628/*!
629 \return true, if attribute is enabled
630 \sa setCurveAttribute()
631*/
632bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const
633{
634 return d_data->attributes & attribute;
635}
636
637/*!
638 Assign a curve fitter
639
640 The curve fitter "smooths" the curve points, when the Fitted
641 CurveAttribute is set. setCurveFitter(NULL) also disables curve fitting.
642
643 The curve fitter operates on the translated points ( = widget coordinates)
644 to be functional for logarithmic scales. Obviously this is less performant
645 for fitting algorithms, that reduce the number of points.
646
647 For situations, where curve fitting is used to improve the performance
648 of painting huge series of points it might be better to execute the fitter
649 on the curve points once and to cache the result in the QwtSeriesData object.
650
651 \param curveFitter() Curve fitter
652 \sa Fitted
653*/
654void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter )
655{
656 delete d_data->curveFitter;
657 d_data->curveFitter = curveFitter;
658
659 itemChanged();
660}
661
662/*!
663 Get the curve fitter. If curve fitting is disabled NULL is returned.
664
665 \return Curve fitter
666 \sa setCurveFitter(), Fitted
667*/
668QwtCurveFitter *QwtPlotCurve::curveFitter() const
669{
670 return d_data->curveFitter;
671}
672
673/*!
674 Fill the area between the curve and the baseline with
675 the curve brush
676
677 \param painter Painter
678 \param xMap x map
679 \param yMap y map
680 \param canvasRect Contents rect of the canvas
681 \param polygon Polygon - will be modified !
682
683 \sa setBrush(), setBaseline(), setStyle()
684*/
685void QwtPlotCurve::fillCurve( QPainter *painter,
686 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
687 const QRectF &canvasRect, QPolygonF &polygon ) const
688{
689 if ( d_data->brush.style() == Qt::NoBrush )
690 return;
691
692 closePolyline( painter, xMap, yMap, polygon );
693 if ( polygon.count() <= 2 ) // a line can't be filled
694 return;
695
696 QBrush brush = d_data->brush;
697 if ( !brush.color().isValid() )
698 brush.setColor( d_data->pen.color() );
699
700 if ( d_data->paintAttributes & ClipPolygons )
701 polygon = QwtClipper::clipPolygonF( canvasRect, polygon, true );
702
703 painter->save();
704
705 painter->setPen( Qt::NoPen );
706 painter->setBrush( brush );
707
708 QwtPainter::drawPolygon( painter, polygon );
709
710 painter->restore();
711}
712
713/*!
714 \brief Complete a polygon to be a closed polygon including the
715 area between the original polygon and the baseline.
716
717 \param painter Painter
718 \param xMap X map
719 \param yMap Y map
720 \param polygon Polygon to be completed
721*/
722void QwtPlotCurve::closePolyline( QPainter *painter,
723 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
724 QPolygonF &polygon ) const
725{
726 if ( polygon.size() < 2 )
727 return;
728
729 const bool doAlign = QwtPainter::roundingAlignment( painter );
730
731 double baseline = d_data->baseline;
732
733 if ( orientation() == Qt::Vertical )
734 {
735 if ( yMap.transformation()->type() == QwtScaleTransformation::Log10 )
736 {
737 if ( baseline < QwtScaleMap::LogMin )
738 baseline = QwtScaleMap::LogMin;
739 }
740
741 double refY = yMap.transform( baseline );
742 if ( doAlign )
743 refY = qRound( refY );
744
745 polygon += QPointF( polygon.last().x(), refY );
746 polygon += QPointF( polygon.first().x(), refY );
747 }
748 else
749 {
750 if ( xMap.transformation()->type() == QwtScaleTransformation::Log10 )
751 {
752 if ( baseline < QwtScaleMap::LogMin )
753 baseline = QwtScaleMap::LogMin;
754 }
755
756 double refX = xMap.transform( baseline );
757 if ( doAlign )
758 refX = qRound( refX );
759
760 polygon += QPointF( refX, polygon.last().y() );
761 polygon += QPointF( refX, polygon.first().y() );
762 }
763}
764
765/*!
766 Draw symbols
767
768 \param painter Painter
769 \param symbol Curve symbol
770 \param xMap x map
771 \param yMap y map
772 \param canvasRect Contents rect of the canvas
773 \param from Index of the first point to be painted
774 \param to Index of the last point to be painted
775
776 \sa setSymbol(), drawSeries(), drawCurve()
777*/
778void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
779 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
780 const QRectF &canvasRect, int from, int to ) const
781{
782 const bool doAlign = QwtPainter::roundingAlignment( painter );
783
784 bool usePixmap = testPaintAttribute( CacheSymbols );
785 if ( usePixmap && !doAlign )
786 {
787 // Don't use the pixmap, when the paint device
788 // could generate scalable vectors
789
790 usePixmap = false;
791 }
792
793 if ( usePixmap )
794 {
795 QPixmap pm( symbol.boundingSize() );
796 pm.fill( Qt::transparent );
797
798 const double pw2 = 0.5 * pm.width();
799 const double ph2 = 0.5 * pm.height();
800
801 QPainter p( &pm );
802 p.setRenderHints( painter->renderHints() );
803 symbol.drawSymbol( &p, QPointF( pw2, ph2 ) );
804 p.end();
805
806 for ( int i = from; i <= to; i++ )
807 {
808 const QPointF sample = d_series->sample( i );
809
810 double xi = xMap.transform( sample.x() );
811 double yi = yMap.transform( sample.y() );
812 if ( doAlign )
813 {
814 xi = qRound( xi );
815 yi = qRound( yi );
816 }
817
818 if ( canvasRect.contains( xi, yi ) )
819 {
820 const int left = qCeil( xi ) - pw2;
821 const int top = qCeil( yi ) - ph2;
822
823 painter->drawPixmap( left, top, pm );
824 }
825 }
826 }
827 else
828 {
829 const int chunkSize = 500;
830
831 for ( int i = from; i <= to; i += chunkSize )
832 {
833 const int n = qMin( chunkSize, to - i + 1 );
834
835 QPolygonF points;
836 for ( int j = 0; j < n; j++ )
837 {
838 const QPointF sample = d_series->sample( i + j );
839
840 const double xi = xMap.transform( sample.x() );
841 const double yi = yMap.transform( sample.y() );
842
843 if ( canvasRect.contains( xi, yi ) )
844 points += QPointF( xi, yi );
845 }
846
847 if ( points.size() > 0 )
848 symbol.drawSymbols( painter, points );
849 }
850 }
851}
852
853/*!
854 \brief Set the value of the baseline
855
856 The baseline is needed for filling the curve with a brush or
857 the Sticks drawing style.
858 The interpretation of the baseline depends on the CurveType.
859 With QwtPlotCurve::Yfx, the baseline is interpreted as a horizontal line
860 at y = baseline(), with QwtPlotCurve::Yfy, it is interpreted as a vertical
861 line at x = baseline().
862
863 The default value is 0.0.
864
865 \param value Value of the baseline
866 \sa baseline(), setBrush(), setStyle(), setStyle()
867*/
868void QwtPlotCurve::setBaseline( double value )
869{
870 if ( d_data->baseline != value )
871 {
872 d_data->baseline = value;
873 itemChanged();
874 }
875}
876
877/*!
878 \return Value of the baseline
879 \sa setBaseline()
880*/
881double QwtPlotCurve::baseline() const
882{
883 return d_data->baseline;
884}
885
886/*!
887 Find the closest curve point for a specific position
888
889 \param pos Position, where to look for the closest curve point
890 \param dist If dist != NULL, closestPoint() returns the distance between
891 the position and the clostest curve point
892 \return Index of the closest curve point, or -1 if none can be found
893 ( f.e when the curve has no points )
894 \note closestPoint() implements a dumb algorithm, that iterates
895 over all points
896*/
897int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const
898{
899 if ( plot() == NULL || dataSize() <= 0 )
900 return -1;
901
902 const QwtScaleMap xMap = plot()->canvasMap( xAxis() );
903 const QwtScaleMap yMap = plot()->canvasMap( yAxis() );
904
905 int index = -1;
906 double dmin = 1.0e10;
907
908 for ( uint i = 0; i < dataSize(); i++ )
909 {
910 const QPointF sample = d_series->sample( i );
911
912 const double cx = xMap.transform( sample.x() ) - pos.x();
913 const double cy = yMap.transform( sample.y() ) - pos.y();
914
915 const double f = qwtSqr( cx ) + qwtSqr( cy );
916 if ( f < dmin )
917 {
918 index = i;
919 dmin = f;
920 }
921 }
922 if ( dist )
923 *dist = qSqrt( dmin );
924
925 return index;
926}
927
928/*!
929 \brief Update the widget that represents the item on the legend
930
931 \param legend Legend
932 \sa drawLegendIdentifier(), legendItem(), QwtPlotItem::Legend
933*/
934void QwtPlotCurve::updateLegend( QwtLegend *legend ) const
935{
936 if ( legend && testItemAttribute( QwtPlotItem::Legend )
937 && ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
938 && d_data->symbol
939 && d_data->symbol->style() != QwtSymbol::NoSymbol )
940 {
941 QWidget *lgdItem = legend->find( this );
942 if ( lgdItem == NULL )
943 {
944 lgdItem = legendItem();
945 if ( lgdItem )
946 legend->insert( this, lgdItem );
947 }
948
949 QwtLegendItem *l = qobject_cast<QwtLegendItem *>( lgdItem );
950 if ( l )
951 {
952 QSize sz = d_data->symbol->boundingSize();
953 sz += QSize( 2, 2 ); // margin
954
955 if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
956 {
957 // Avoid, that the line is completely covered by the symbol
958
959 int w = qCeil( 1.5 * sz.width() );
960 if ( w % 2 )
961 w++;
962
963 sz.setWidth( qMax( 8, w ) );
964 }
965
966 l->setIdentifierSize( sz );
967 }
968 }
969
970 QwtPlotItem::updateLegend( legend );
971}
972
973/*!
974 \brief Draw the identifier representing the curve on the legend
975
976 \param painter Painter
977 \param rect Bounding rectangle for the identifier
978
979 \sa setLegendAttribute(), QwtPlotItem::Legend
980*/
981void QwtPlotCurve::drawLegendIdentifier(
982 QPainter *painter, const QRectF &rect ) const
983{
984 if ( rect.isEmpty() )
985 return;
986
987 const int dim = qMin( rect.width(), rect.height() );
988
989 QSize size( dim, dim );
990
991 QRectF r( 0, 0, size.width(), size.height() );
992 r.moveCenter( rect.center() );
993
994 if ( d_data->legendAttributes == 0 )
995 {
996 QBrush brush = d_data->brush;
997 if ( brush.style() == Qt::NoBrush )
998 {
999 if ( style() != QwtPlotCurve::NoCurve )
1000 brush = QBrush( pen().color() );
1001 else if ( d_data->symbol &&
1002 ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
1003 {
1004 brush = QBrush( d_data->symbol->pen().color() );
1005 }
1006 }
1007 if ( brush.style() != Qt::NoBrush )
1008 painter->fillRect( r, brush );
1009 }
1010 if ( d_data->legendAttributes & QwtPlotCurve::LegendShowBrush )
1011 {
1012 if ( d_data->brush.style() != Qt::NoBrush )
1013 painter->fillRect( r, d_data->brush );
1014 }
1015 if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
1016 {
1017 if ( pen() != Qt::NoPen )
1018 {
1019 painter->setPen( pen() );
1020 QwtPainter::drawLine( painter, rect.left(), rect.center().y(),
1021 rect.right() - 1.0, rect.center().y() );
1022 }
1023 }
1024 if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
1025 {
1026 if ( d_data->symbol &&
1027 ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
1028 {
1029 QSize symbolSize = d_data->symbol->boundingSize();
1030 symbolSize -= QSize( 2, 2 );
1031
1032 // scale the symbol size down if it doesn't fit into rect.
1033
1034 double xRatio = 1.0;
1035 if ( rect.width() < symbolSize.width() )
1036 xRatio = rect.width() / symbolSize.width();
1037 double yRatio = 1.0;
1038 if ( rect.height() < symbolSize.height() )
1039 yRatio = rect.height() / symbolSize.height();
1040
1041 const double ratio = qMin( xRatio, yRatio );
1042
1043 painter->save();
1044 painter->scale( ratio, ratio );
1045
1046 d_data->symbol->drawSymbol( painter, rect.center() / ratio );
1047
1048 painter->restore();
1049 }
1050 }
1051}
1052
1053/*!
1054 Initialize data with an array of points (explicitly shared).
1055
1056 \param samples Vector of points
1057*/
1058void QwtPlotCurve::setSamples( const QVector<QPointF> &samples )
1059{
1060 delete d_series;
1061 d_series = new QwtPointSeriesData( samples );
1062 itemChanged();
1063}
1064
1065#ifndef QWT_NO_COMPAT
1066
1067/*!
1068 \brief Initialize the data by pointing to memory blocks which
1069 are not managed by QwtPlotCurve.
1070
1071 setRawSamples is provided for efficiency.
1072 It is important to keep the pointers
1073 during the lifetime of the underlying QwtCPointerData class.
1074
1075 \param xData pointer to x data
1076 \param yData pointer to y data
1077 \param size size of x and y
1078
1079 \sa QwtCPointerData
1080*/
1081void QwtPlotCurve::setRawSamples(
1082 const double *xData, const double *yData, int size )
1083{
1084 delete d_series;
1085 d_series = new QwtCPointerData( xData, yData, size );
1086 itemChanged();
1087}
1088
1089/*!
1090 Set data by copying x- and y-values from specified memory blocks.
1091 Contrary to setRawSamples(), this function makes a 'deep copy' of
1092 the data.
1093
1094 \param xData pointer to x values
1095 \param yData pointer to y values
1096 \param size size of xData and yData
1097
1098 \sa QwtPointArrayData
1099*/
1100void QwtPlotCurve::setSamples(
1101 const double *xData, const double *yData, int size )
1102{
1103 delete d_series;
1104 d_series = new QwtPointArrayData( xData, yData, size );
1105 itemChanged();
1106}
1107
1108/*!
1109 \brief Initialize data with x- and y-arrays (explicitly shared)
1110
1111 \param xData x data
1112 \param yData y data
1113
1114 \sa QwtPointArrayData
1115*/
1116void QwtPlotCurve::setSamples( const QVector<double> &xData,
1117 const QVector<double> &yData )
1118{
1119 delete d_series;
1120 d_series = new QwtPointArrayData( xData, yData );
1121 itemChanged();
1122}
1123#endif // !QWT_NO_COMPAT
1124
Note: See TracBrowser for help on using the repository browser.