qwt_plot_curve.cpp 29 KB

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