PDA

View Full Version : Make a partial replot using reimplemented QwtPlot::replot()



Momergil
13th May 2014, 13:16
Hello!

Is there a way for doing a partial replot using a reimplemented QwtPlot::replot()? This partial replot would be essentially to tell which area of the graph I want to be reploted instead of the entire canvas.

I noticed the code for QwtPlot::replot() in 6.1.0 is:



void QwtPlot::replot()
{
bool doAutoReplot = autoReplot();
setAutoReplot( false );

updateAxes();

/*
Maybe the layout needs to be updated, because of changed
axes labels. We need to process them here before painting
to avoid that scales and canvas get out of sync.
*/
QApplication::sendPostedEvents( this, QEvent::LayoutRequest );

if ( d_data->canvas )
{
const bool ok = QMetaObject::invokeMethod(
d_data->canvas, "replot", Qt::DirectConnection );
if ( !ok )
{
// fallback, when canvas has no a replot method
d_data->canvas->update( d_data->canvas->contentsRect() );
}
}

setAutoReplot( doAutoReplot );
}


When I tried, the problems arised when considering the "replot" method of the canvas:



void QwtPlotCanvas::replot()
{
invalidateBackingStore();

if ( testPaintAttribute( QwtPlotCanvas::ImmediatePaint ) )
repaint( contentsRect() );
else
update( contentsRect() );
}


If I understood correctly, I'll have to create a new QwtPlotCanvas for my custom QwtPlot with a reimplemented replot() method in which instead of using contentsRect(), I'll use a QRect with customized form previously set by a new method.

Is this all ok or did I miss something?


Thanks,

Momergil

Uwe
14th May 2014, 07:57
Assuming that you have new curve points in the area [x1,x2] ( in plot coordinates ) and the backingstore ( QwtPlotCanvas::BackingStore ) of the canvas is disabled:



void updatePlot( QwtPlot* plot, double x1, double x2 )
{
const QwtScaleMap xMap = plot->canvasMap( QwtPlot::xBottom );

const int l = xMap.transform( x1 );
const int r = xMap.transform( x2 );
const QRect cr = plot->canvas()->contentsRect();

plot->canvas()->repaint( l, cr.y(), r - l, cr,height() );
}
The rectangle you have passed to the paint event will end up as clip region of the painter and you could overload QwtPlot::drawItems():


virtual void YourPlot::drawItems( QPainter *painter, const QRectF &canvasRect,
const QwtScaleMap maps[axisCnt] ) const
{
const QRectF rect = painter->clipRegion().boundingRect();

// rect should have been filled with the background of the canvas
// before. When you have other plot items ( f.e. a grid ) you have to restore
// them for rect() too.

...

double x1 = maps[curve->xAxis()].invTransform( rect.x() );
double x2 = maps[curve->xAxis()].invTransform( rect.x() + rect.width() );

// find the segment of your curve for [x1, x2]
// f.e. using qwtUpperSampleIndex() ?

int from = ...;
int to = ...

curve->drawSeries( painter,
maps[curve->xAxis()], maps[curve->yAxis()], canvasRect, from, to );
}

You could try to use QwtPlotGLCanvas, that offers hardware acceleration and its limitations should be no big issue for your type of application. For QwtPlotCanvas ( = anything derived from QWidget ) there is only Qt4/X11 ( native graphicssystem ) where you have hardware acceleration.

Uwe