Results 1 to 7 of 7

Thread: Improve performance for realtime moving marker?

  1. #1
    Join Date
    Jan 2009
    Posts
    17
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Improve performance for realtime moving marker?

    Hello,

    I have a plot (see attachment) which shows data over timeline. I use a panner and magnifier for user interaction. In addition I have a realtime 'player' (timer) which updates a time marker walking over the plot. The marker is updated every 100ms. Actually a QwtPlotMarker is used. As we need to replot() every time when the position of the marker changes, the application becomes slow, depending on the number of plot curves and the timer interval. The number of plot curves is generically variable and can be more than 10.

    Is there any idea how to get the same view with better performance?

    Best Regards
    Stefan
    Attached Images Attached Images

  2. #2
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,313
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Improve performance for realtime moving marker?

    a) One possible solution is to introduce a pixmap cache for all plot items with a smaller z value than the marker. This can be done by overloading QwtPlot::drawItems. When you also overload QwtPlotItem::itemChanged() for all items that should be cached, you can invalidate your cache easily. ( I guess then it is better to disable the builtin cache of the canvas. )

    b) Another solution is to implement an overlay widget ( like the rubberband in the picker ).

    Uwe

  3. #3
    Join Date
    Jan 2009
    Posts
    17
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Improve performance for realtime moving marker?

    Hello again

    I'm still trying to solve that problem. There is one big issue which I don't know how to solve . The methods to overwrite are all const!

    In my PlotCurve class I do:
    Qt Code:
    1. void PlotCurve::itemChanged(void)
    2. {
    3. QwtPlotCurve::itemChanged();
    4. if(plot())
    5. {
    6. ((Plot*)plot())->invalidateCache();
    7. }
    8. }
    To copy to clipboard, switch view to plain text mode 

    In my Plot class I would like to do:
    Qt Code:
    1. void Plot::invalidateCache(void)
    2. {
    3. mPixmapCache = new QPixmap();
    4. }
    5.  
    6. void Plot::drawItems(QPainter *pPainter, const QRect &pRect, const QwtScaleMap pMap[QwtPlot::axisCnt], const QwtPlotPrintFilter &pFilter) const
    7. {
    8. QwtPlotItemList lAlwaysDrawnItems;
    9. bool lCacheValid = !mPixmapCache->isNull();
    10. if(!lCacheValid)
    11. {
    12. // Error here: assignment of data-member `Plot::mPixmapCache' in read-only structure
    13. mPixmapCache = new QPixmap(pRect.size());
    14. }
    15. QPainter lCachePainter(mPixmapCache);
    16.  
    17. const QwtPlotItemList& lItemList = itemList();
    18. for (QwtPlotItemIterator lItemIter = lItemList.begin(); lItemIter != lItemList.end(); ++lItemIter)
    19. {
    20. QwtPlotItem *lItem = *lItemIter;
    21. if (lItem && lItem->isVisible() )
    22. {
    23. if ( !(pFilter.options() & QwtPlotPrintFilter::PrintGrid) && lItem->rtti() == QwtPlotItem::Rtti_PlotGrid)
    24. {
    25. continue;
    26. }
    27. // render items below z-index 1000 when cache is empty only
    28. if(lItem->z() < 1000)
    29. {
    30. if(!lCacheValid)
    31. {
    32. lCachePainter.save();
    33. lCachePainter.setRenderHint(QPainter::Antialiasing, lItem->testRenderHint(QwtPlotItem::RenderAntialiased));
    34. lItem->draw(&lCachePainter, pMap[lItem->xAxis()], pMap[lItem->yAxis()], pRect);
    35. lCachePainter.restore();
    36. }
    37. }
    38. else
    39. {
    40. lAlwaysDrawnItems.append(lItem);
    41. }
    42. }
    43. }
    44.  
    45. pPainter->drawPixmap(contentsRect().topLeft(), *mPixmapCache);
    46.  
    47. for (QwtPlotItemIterator lItemIter = lAlwaysDrawnItems.begin(); lItemIter != lAlwaysDrawnItems.end(); ++lItemIter)
    48. {
    49. QwtPlotItem *lItem = *lItemIter;
    50. pPainter->save();
    51. pPainter->setRenderHint(QPainter::Antialiasing, lItem->testRenderHint(QwtPlotItem::RenderAntialiased));
    52. lItem->draw(pPainter, pMap[lItem->xAxis()], pMap[lItem->yAxis()], pRect);
    53. pPainter->restore();
    54. }
    55. }
    To copy to clipboard, switch view to plain text mode 

    What can I do to get rid of the "assignment of data-member `Plot::mPixmapCache' in read-only structure" error?

    Best Regards
    Stefan
    Last edited by StefanK; 2nd March 2009 at 12:22. Reason: spelling error

  4. #4
    Join Date
    Jan 2009
    Posts
    17
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Improve performance for realtime moving marker?

    A possible solution seems to be to make the drawItems method with the user code non const and to call it from another overriding const drawItems method after a brute force const_cast of the this pointer.
    Qt Code:
    1. void Plot::drawItems(QPainter *pPainter, const QRect &pRect, const QwtScaleMap pMap[QwtPlot::axisCnt], const QwtPlotPrintFilter &pFilter) const
    2. {
    3. Plot* lAccessiblePlot = const_cast<Plot*>(this);
    4. lAccessiblePlot->drawItems(pPainter,pRect,pMap,pFilter);
    5. }
    6.  
    7. void Plot::drawItems(QPainter *pPainter, const QRect &pRect, const QwtScaleMap pMap[QwtPlot::axisCnt], const QwtPlotPrintFilter &pFilter)
    8. {
    9. // the user implementation of drawItems
    10. }
    To copy to clipboard, switch view to plain text mode 

  5. #5
    Join Date
    Jan 2009
    Posts
    17
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Improve performance for realtime moving marker?

    Hello again,

    Still one question. I get the debug output from Qt: "QWidget::repaint: Recursive repaint detected" "QPainter::begin: A paint device can only be painted by one painter at a time."

    I adapted the code as follows. The message is emited when calling grabWidget() to save the content to the cache. Any idea why and how to correct?
    Qt Code:
    1. void Plot::drawItems(QPainter *pPainter, const QRect &pRect, const QwtScaleMap pMap[QwtPlot::axisCnt], const QwtPlotPrintFilter &pFilter)
    2. {
    3. QwtPlotItemList lAlwaysDrawnItems;
    4. // null pixmap means cache not valid
    5. bool lCacheValid = !mPixmapCache->isNull();
    6.  
    7. const QwtPlotItemList& lItemList = itemList();
    8. for (QwtPlotItemIterator lItemIter = lItemList.begin(); lItemIter != lItemList.end(); ++lItemIter)
    9. {
    10. QwtPlotItem *lItem = *lItemIter;
    11. if (lItem && lItem->isVisible() )
    12. {
    13. if ( !(pFilter.options() & QwtPlotPrintFilter::PrintGrid) && lItem->rtti() == QwtPlotItem::Rtti_PlotGrid)
    14. {
    15. continue;
    16. }
    17. // render items below z-index 1000
    18. // when cache is invalid only
    19. if(lItem->z() < 1000)
    20. {
    21. if(!lCacheValid)
    22. {
    23. pPainter->save();
    24. pPainter->setRenderHint(QPainter::Antialiasing, lItem->testRenderHint(QwtPlotItem::RenderAntialiased));
    25. lItem->draw(pPainter, pMap[lItem->xAxis()], pMap[lItem->yAxis()], pRect);
    26. pPainter->restore();
    27. }
    28. }
    29. else
    30. {
    31. // all items above z-index 1000 are added to a list in order to draw after cache content
    32. lAlwaysDrawnItems.append(lItem);
    33. }
    34. }
    35. }
    36.  
    37. if(lCacheValid)
    38. {
    39. // if cache has been valid then paint from pixmap cache
    40. pPainter->drawPixmap(pRect, *mPixmapCache);
    41. }
    42. else
    43. {
    44. // create new pixmap when cache not valid
    45. mPixmapCache = new QPixmap(pRect.size());
    46. // else make a snapshot from the plot canvas curves
    47. *mPixmapCache = QPixmap::grabWidget(canvas(), pRect);
    48. }
    49.  
    50. // finally draw the rest to be rendered each time (z-index > 1000)
    51. for (QwtPlotItemIterator lItemIter = lAlwaysDrawnItems.begin(); lItemIter != lAlwaysDrawnItems.end(); ++lItemIter)
    52. {
    53. QwtPlotItem *lItem = *lItemIter;
    54. pPainter->save();
    55. pPainter->setRenderHint(QPainter::Antialiasing, lItem->testRenderHint(QwtPlotItem::RenderAntialiased));
    56. lItem->draw(pPainter, pMap[lItem->xAxis()], pMap[lItem->yAxis()], pRect);
    57. pPainter->restore();
    58. }
    59. }
    To copy to clipboard, switch view to plain text mode 

    Any suggestion for improvement appreciated.

    Best Regards
    Stefan
    Last edited by StefanK; 3rd March 2009 at 06:11.

  6. #6
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,313
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Improve performance for realtime moving marker?

    a) grabWidget triggers a repaint of the widget with a redirected QPainter. This will never work when you call it in QPaintEvent.

    b) Better paint your cached items to a image/pixmap with a transparent background. This can be painted later easily between background and your marker.

    c) Maybe QwtPlotCanvas::paintCache is of use. Look how it is implemented in Qwt. It could help to find out how you can setup your own cache.

    d) To avoid constness problems with your pixmap cache declare it as "mutable". ( See in your C++ reference if you never heard of it ).

    Uwe

  7. The following user says thank you to Uwe for this useful post:

    StefanK (5th March 2009)

  8. #7
    Join Date
    Jan 2009
    Posts
    17
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Improve performance for realtime moving marker?

    Thank you Uwe!

    d) I found it (Stroustrup, page 223)

    As work arround I get the pixmap now from the canvas cache. That works fine and I get a lot faster plot. May be there are better ways as you suggested in d) as we could disable the canvas cache. I will check that later.

    Qt Code:
    1. void Plot::drawItems(QPainter *pPainter, const QRect &pRect, const QwtScaleMap pMap[QwtPlot::axisCnt], const QwtPlotPrintFilter &pFilter) const
    2. {
    3. QwtPlotItemList lAlwaysDrawnItems;
    4. // null pixmap means cache not valid
    5. bool lCacheValid = !mPixmapCache->isNull();
    6.  
    7. const QwtPlotItemList& lItemList = itemList();
    8. for (QwtPlotItemIterator lItemIter = lItemList.begin(); lItemIter != lItemList.end(); ++lItemIter)
    9. {
    10. QwtPlotItem *lItem = *lItemIter;
    11. if (lItem && lItem->isVisible() )
    12. {
    13. if ( !(pFilter.options() & QwtPlotPrintFilter::PrintGrid) && lItem->rtti() == QwtPlotItem::Rtti_PlotGrid)
    14. {
    15. continue;
    16. }
    17. // render items below z-index 1000
    18. // when cache is invalid only
    19. if(lItem->z() < 1000)
    20. {
    21. if(!lCacheValid)
    22. {
    23. pPainter->save();
    24. pPainter->setRenderHint(QPainter::Antialiasing, lItem->testRenderHint(QwtPlotItem::RenderAntialiased));
    25. lItem->draw(pPainter, pMap[lItem->xAxis()], pMap[lItem->yAxis()], pRect);
    26. pPainter->restore();
    27. }
    28. }
    29. else
    30. {
    31. // all items above z-index 1000 are added to a list in order to draw after cache content
    32. lAlwaysDrawnItems.append(lItem);
    33. }
    34. }
    35. }
    36.  
    37. if(lCacheValid)
    38. {
    39. // if cache has been valid then paint from pixmap cache
    40. pPainter->drawPixmap(pRect.topLeft(), *mPixmapCache);
    41. }
    42. else
    43. {
    44. mPixmapCache = new QPixmap(*canvas()->paintCache());
    45. }
    46.  
    47. // finally draw the rest to be rendered each time (z-index > 1000)
    48. for (QwtPlotItemIterator lItemIter = lAlwaysDrawnItems.begin(); lItemIter != lAlwaysDrawnItems.end(); ++lItemIter)
    49. {
    50. QwtPlotItem *lItem = *lItemIter;
    51. pPainter->save();
    52. pPainter->setRenderHint(QPainter::Antialiasing, lItem->testRenderHint(QwtPlotItem::RenderAntialiased));
    53. lItem->draw(pPainter, pMap[lItem->xAxis()], pMap[lItem->yAxis()], pRect);
    54. pPainter->restore();
    55. }
    56. }
    To copy to clipboard, switch view to plain text mode 

    Best Regards
    Stefan

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.