Loading...
Searching...
No Matches
qwt_plot_rescaler.cpp
/******************************************************************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_plot_rescaler.h"
#include "qwt_plot.h"
#include "qwt_scale_div.h"
#include "qwt_interval.h"
#include "qwt_plot_canvas.h"
#include <qevent.h>
class QwtPlotRescaler::AxisData
{
public:
AxisData()
: aspectRatio( 1.0 )
, expandingDirection( QwtPlotRescaler::ExpandUp )
{
}
double aspectRatio;
QwtInterval intervalHint;
QwtPlotRescaler::ExpandingDirection expandingDirection;
mutable QwtScaleDiv scaleDiv;
};
class QwtPlotRescaler::PrivateData
{
public:
PrivateData()
: referenceAxis( QwtAxis::XBottom )
, rescalePolicy( QwtPlotRescaler::Expanding )
, isEnabled( false )
, inReplot( 0 )
{
}
QwtPlotRescaler::AxisData* axisData( QwtAxisId axisId )
{
if ( !QwtAxis::isValid( axisId ) )
return NULL;
return &m_axisData[ axisId];
}
QwtAxisId referenceAxis;
RescalePolicy rescalePolicy;
bool isEnabled;
mutable int inReplot;
private:
QwtPlotRescaler::AxisData m_axisData[QwtAxis::AxisPositions];
};
QwtPlotRescaler::QwtPlotRescaler( QWidget* canvas,
QwtAxisId referenceAxis, RescalePolicy policy )
: QObject( canvas )
{
m_data = new PrivateData;
m_data->referenceAxis = referenceAxis;
m_data->rescalePolicy = policy;
setEnabled( true );
}
QwtPlotRescaler::~QwtPlotRescaler()
{
delete m_data;
}
void QwtPlotRescaler::setEnabled( bool on )
{
if ( m_data->isEnabled != on )
{
m_data->isEnabled = on;
QWidget* w = canvas();
if ( w )
{
if ( m_data->isEnabled )
w->installEventFilter( this );
else
w->removeEventFilter( this );
}
}
}
bool QwtPlotRescaler::isEnabled() const
{
return m_data->isEnabled;
}
void QwtPlotRescaler::setRescalePolicy( RescalePolicy policy )
{
m_data->rescalePolicy = policy;
}
QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const
{
return m_data->rescalePolicy;
}
void QwtPlotRescaler::setReferenceAxis( QwtAxisId axisId )
{
m_data->referenceAxis = axisId;
}
QwtAxisId QwtPlotRescaler::referenceAxis() const
{
return m_data->referenceAxis;
}
void QwtPlotRescaler::setExpandingDirection(
ExpandingDirection direction )
{
for ( int axis = 0; axis < QwtAxis::AxisPositions; axis++ )
setExpandingDirection( axis, direction );
}
void QwtPlotRescaler::setExpandingDirection(
QwtAxisId axisId, ExpandingDirection direction )
{
if ( AxisData* axisData = m_data->axisData( axisId ) )
axisData->expandingDirection = direction;
}
QwtPlotRescaler::ExpandingDirection
QwtPlotRescaler::expandingDirection( QwtAxisId axisId ) const
{
if ( const AxisData* axisData = m_data->axisData( axisId ) )
return axisData->expandingDirection;
return ExpandBoth;
}
void QwtPlotRescaler::setAspectRatio( double ratio )
{
for ( int axis = 0; axis < QwtAxis::AxisPositions; axis++ )
setAspectRatio( axis, ratio );
}
void QwtPlotRescaler::setAspectRatio( QwtAxisId axisId, double ratio )
{
if ( AxisData* axisData = m_data->axisData( axisId ) )
{
if ( ratio < 0.0 )
ratio = 0.0;
axisData->aspectRatio = ratio;
}
}
double QwtPlotRescaler::aspectRatio( QwtAxisId axisId ) const
{
if ( AxisData* axisData = m_data->axisData( axisId ) )
return axisData->aspectRatio;
return 0.0;
}
void QwtPlotRescaler::setIntervalHint( QwtAxisId axisId,
const QwtInterval& interval )
{
if ( AxisData* axisData = m_data->axisData( axisId ) )
axisData->intervalHint = interval;
}
QwtInterval QwtPlotRescaler::intervalHint( QwtAxisId axisId ) const
{
if ( AxisData* axisData = m_data->axisData( axisId ) )
return axisData->intervalHint;
return QwtInterval();
}
QWidget* QwtPlotRescaler::canvas()
{
return qobject_cast< QWidget* >( parent() );
}
const QWidget* QwtPlotRescaler::canvas() const
{
return qobject_cast< const QWidget* >( parent() );
}
QwtPlot* QwtPlotRescaler::plot()
{
QWidget* w = canvas();
if ( w )
w = w->parentWidget();
return qobject_cast< QwtPlot* >( w );
}
const QwtPlot* QwtPlotRescaler::plot() const
{
const QWidget* w = canvas();
if ( w )
w = w->parentWidget();
return qobject_cast< const QwtPlot* >( w );
}
bool QwtPlotRescaler::eventFilter( QObject* object, QEvent* event )
{
if ( object && object == canvas() )
{
switch ( event->type() )
{
case QEvent::Resize:
{
canvasResizeEvent( static_cast< QResizeEvent* >( event ) );
break;
}
case QEvent::PolishRequest:
{
rescale();
break;
}
default:;
}
}
return false;
}
void QwtPlotRescaler::canvasResizeEvent( QResizeEvent* event )
{
const QMargins m = canvas()->contentsMargins();
const QSize marginSize( m.left() + m.right(), m.top() + m.bottom() );
const QSize newSize = event->size() - marginSize;
const QSize oldSize = event->oldSize() - marginSize;
rescale( oldSize, newSize );
}
void QwtPlotRescaler::rescale() const
{
const QSize size = canvas()->contentsRect().size();
rescale( size, size );
}
void QwtPlotRescaler::rescale(
const QSize& oldSize, const QSize& newSize ) const
{
if ( newSize.isEmpty() )
return;
QwtInterval intervals[QwtAxis::AxisPositions];
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
const QwtAxisId axisId( axisPos );
intervals[axisPos] = interval( axisId );
}
const QwtAxisId refAxis = referenceAxis();
intervals[refAxis] = expandScale( refAxis, oldSize, newSize );
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
const QwtAxisId axisId( axisPos );
if ( aspectRatio( axisId ) > 0.0 && axisId != refAxis )
{
intervals[axisPos] = syncScale(
axisId, intervals[refAxis], newSize );
}
}
updateScales( intervals );
}
QwtInterval QwtPlotRescaler::expandScale( QwtAxisId axisId,
const QSize& oldSize, const QSize& newSize ) const
{
const QwtInterval oldInterval = interval( axisId );
QwtInterval expanded = oldInterval;
switch ( rescalePolicy() )
{
case Fixed:
{
break; // do nothing
}
case Expanding:
{
if ( !oldSize.isEmpty() )
{
double width = oldInterval.width();
if ( orientation( axisId ) == Qt::Horizontal )
width *= double( newSize.width() ) / oldSize.width();
else
width *= double( newSize.height() ) / oldSize.height();
expanded = expandInterval( oldInterval,
width, expandingDirection( axisId ) );
}
break;
}
case Fitting:
{
double dist = 0.0;
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
const QwtAxisId axisId( axisPos );
const double d = pixelDist( axisId, newSize );
if ( d > dist )
dist = d;
}
if ( dist > 0.0 )
{
double width;
if ( orientation( axisId ) == Qt::Horizontal )
width = newSize.width() * dist;
else
width = newSize.height() * dist;
expanded = expandInterval( intervalHint( axisId ),
width, expandingDirection( axisId ) );
}
break;
}
}
return expanded;
}
QwtInterval QwtPlotRescaler::syncScale( QwtAxisId axisId,
const QwtInterval& reference, const QSize& size ) const
{
double dist;
if ( orientation( referenceAxis() ) == Qt::Horizontal )
dist = reference.width() / size.width();
else
dist = reference.width() / size.height();
if ( orientation( axisId ) == Qt::Horizontal )
dist *= size.width();
else
dist *= size.height();
dist /= aspectRatio( axisId );
QwtInterval intv;
if ( rescalePolicy() == Fitting )
intv = intervalHint( axisId );
else
intv = interval( axisId );
intv = expandInterval( intv, dist, expandingDirection( axisId ) );
return intv;
}
Qt::Orientation QwtPlotRescaler::orientation( QwtAxisId axisId ) const
{
return QwtAxis::isYAxis( axisId ) ? Qt::Vertical : Qt::Horizontal;
}
QwtInterval QwtPlotRescaler::interval( QwtAxisId axisId ) const
{
if ( !plot()->isAxisValid( axisId ) )
return QwtInterval();
return plot()->axisScaleDiv( axisId ).interval().normalized();
}
QwtInterval QwtPlotRescaler::expandInterval(
const QwtInterval& interval, double width,
ExpandingDirection direction ) const
{
QwtInterval expanded = interval;
switch ( direction )
{
case ExpandUp:
expanded.setMinValue( interval.minValue() );
expanded.setMaxValue( interval.minValue() + width );
break;
case ExpandDown:
expanded.setMaxValue( interval.maxValue() );
expanded.setMinValue( interval.maxValue() - width );
break;
case ExpandBoth:
default:
expanded.setMinValue( interval.minValue() +
interval.width() / 2.0 - width / 2.0 );
expanded.setMaxValue( expanded.minValue() + width );
}
return expanded;
}
double QwtPlotRescaler::pixelDist( QwtAxisId axisId, const QSize& size ) const
{
const QwtInterval intv = intervalHint( axisId );
double dist = 0.0;
if ( !intv.isNull() )
{
if ( axisId == referenceAxis() )
{
dist = intv.width();
}
else
{
const double r = aspectRatio( axisId );
if ( r > 0.0 )
dist = intv.width() * r;
}
}
if ( dist > 0.0 )
{
if ( orientation( axisId ) == Qt::Horizontal )
dist /= size.width();
else
dist /= size.height();
}
return dist;
}
void QwtPlotRescaler::updateScales(
QwtInterval intervals[QwtAxis::AxisPositions] ) const
{
if ( m_data->inReplot >= 5 )
{
return;
}
QwtPlot* plt = const_cast< QwtPlot* >( plot() );
const bool doReplot = plt->autoReplot();
plt->setAutoReplot( false );
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
{
const QwtAxisId axisId( axisPos );
if ( axisId == referenceAxis() || aspectRatio( axisId ) > 0.0 )
{
double v1 = intervals[axisPos].minValue();
double v2 = intervals[axisPos].maxValue();
if ( !plt->axisScaleDiv( axisId ).isIncreasing() )
qSwap( v1, v2 );
if ( m_data->inReplot >= 1 )
m_data->axisData( axisId )->scaleDiv = plt->axisScaleDiv( axisId );
if ( m_data->inReplot >= 2 )
{
QList< double > ticks[QwtScaleDiv::NTickTypes];
for ( int t = 0; t < QwtScaleDiv::NTickTypes; t++ )
ticks[t] = m_data->axisData( axisId )->scaleDiv.ticks( t );
plt->setAxisScaleDiv( axisId, QwtScaleDiv( v1, v2, ticks ) );
}
else
{
plt->setAxisScale( axisId, v1, v2 );
}
}
}
}
QwtPlotCanvas* canvas = qobject_cast< QwtPlotCanvas* >( plt->canvas() );
bool immediatePaint = false;
if ( canvas )
{
immediatePaint = canvas->testPaintAttribute( QwtPlotCanvas::ImmediatePaint );
canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false );
}
plt->setAutoReplot( doReplot );
m_data->inReplot++;
plt->replot();
m_data->inReplot--;
if ( canvas && immediatePaint )
{
canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true );
}
}
#include "moc_qwt_plot_rescaler.cpp"
QList< double >
QwtInterval
A class representing an interval.
Definition qwt_interval.h:23
QwtInterval::minValue
double minValue() const
Definition qwt_interval.h:192
QwtInterval::normalized
QwtInterval normalized() const
Normalize the limits of the interval.
Definition qwt_interval.cpp:29
QwtInterval::width
double width() const
Return the width of an interval.
Definition qwt_interval.h:227
QwtInterval::setMaxValue
void setMaxValue(double)
Definition qwt_interval.h:186
QwtInterval::maxValue
double maxValue() const
Definition qwt_interval.h:198
QwtInterval::setMinValue
void setMinValue(double)
Definition qwt_interval.h:176
QwtInterval::isNull
bool isNull() const
Definition qwt_interval.h:314
QwtPlotCanvas
Canvas of a QwtPlot.
Definition qwt_plot_canvas.h:30
QwtPlotCanvas::ImmediatePaint
@ ImmediatePaint
Definition qwt_plot_canvas.h:99
QwtPlot
A 2-D plotting widget.
Definition qwt_plot.h:79
QwtPlot::setAxisScale
void setAxisScale(QwtAxisId, double min, double max, double stepSize=0)
Disable autoscaling and specify a fixed scale for a selected axis.
Definition qwt_plot_axis.cpp:477
QwtPlot::autoReplot
bool autoReplot() const
Definition qwt_plot.cpp:319
QwtPlot::canvas
QWidget * canvas()
Definition qwt_plot.cpp:463
QwtPlot::replot
virtual void replot()
Redraw the plot.
Definition qwt_plot.cpp:545
QwtPlot::setAutoReplot
void setAutoReplot(bool=true)
Set or reset the autoReplot option.
Definition qwt_plot.cpp:310
QwtPlot::axisScaleDiv
const QwtScaleDiv & axisScaleDiv(QwtAxisId) const
Return the scale division of a specified axis.
Definition qwt_plot_axis.cpp:283
QwtPlot::setAxisScaleDiv
void setAxisScaleDiv(QwtAxisId, const QwtScaleDiv &)
Disable autoscaling and specify a fixed scale for a selected axis.
Definition qwt_plot_axis.cpp:506
QwtPlotRescaler
QwtPlotRescaler takes care of fixed aspect ratios for plot scales.
Definition qwt_plot_rescaler.h:30
QwtPlotRescaler::referenceAxis
QwtAxisId referenceAxis() const
Definition qwt_plot_rescaler.cpp:158
QwtPlotRescaler::setIntervalHint
void setIntervalHint(QwtAxisId, const QwtInterval &)
Definition qwt_plot_rescaler.cpp:261
QwtPlotRescaler::intervalHint
QwtInterval intervalHint(QwtAxisId) const
Definition qwt_plot_rescaler.cpp:273
QwtPlotRescaler::ExpandingDirection
ExpandingDirection
Definition qwt_plot_rescaler.h:71
QwtPlotRescaler::ExpandUp
@ ExpandUp
The upper limit of the scale is adjusted.
Definition qwt_plot_rescaler.h:73
QwtPlotRescaler::ExpandBoth
@ ExpandBoth
Both limits of the scale are adjusted.
Definition qwt_plot_rescaler.h:79
QwtPlotRescaler::ExpandDown
@ ExpandDown
The lower limit of the scale is adjusted.
Definition qwt_plot_rescaler.h:76
QwtPlotRescaler::expandingDirection
ExpandingDirection expandingDirection(QwtAxisId) const
Definition qwt_plot_rescaler.cpp:197
QwtPlotRescaler::setAspectRatio
void setAspectRatio(double ratio)
Definition qwt_plot_rescaler.cpp:212
QwtPlotRescaler::expandInterval
QwtInterval expandInterval(const QwtInterval &, double width, ExpandingDirection) const
Definition qwt_plot_rescaler.cpp:526
QwtPlotRescaler::expandScale
virtual QwtInterval expandScale(QwtAxisId, const QSize &oldSize, const QSize &newSize) const
Definition qwt_plot_rescaler.cpp:405
QwtPlotRescaler::canvasResizeEvent
virtual void canvasResizeEvent(QResizeEvent *)
Definition qwt_plot_rescaler.cpp:343
QwtPlotRescaler::eventFilter
virtual bool eventFilter(QObject *, QEvent *) override
Event filter for the plot canvas.
Definition qwt_plot_rescaler.cpp:314
QwtPlotRescaler::RescalePolicy
RescalePolicy
Definition qwt_plot_rescaler.h:41
QwtPlotRescaler::Fitting
@ Fitting
Definition qwt_plot_rescaler.h:63
QwtPlotRescaler::Fixed
@ Fixed
Definition qwt_plot_rescaler.h:47
QwtPlotRescaler::Expanding
@ Expanding
Definition qwt_plot_rescaler.h:57
QwtPlotRescaler::setEnabled
void setEnabled(bool)
En/disable the rescaler.
Definition qwt_plot_rescaler.cpp:97
QwtPlotRescaler::orientation
Qt::Orientation orientation(QwtAxisId) const
Definition qwt_plot_rescaler.cpp:500
QwtPlotRescaler::interval
QwtInterval interval(QwtAxisId) const
Definition qwt_plot_rescaler.cpp:509
QwtPlotRescaler::updateScales
virtual void updateScales(QwtInterval intervals[QwtAxis::AxisPositions]) const
Definition qwt_plot_rescaler.cpp:588
QwtPlotRescaler::syncScale
virtual QwtInterval syncScale(QwtAxisId, const QwtInterval &reference, const QSize &size) const
Definition qwt_plot_rescaler.cpp:469
QwtPlotRescaler::isEnabled
bool isEnabled() const
Definition qwt_plot_rescaler.cpp:118
QwtPlotRescaler::aspectRatio
double aspectRatio(QwtAxisId) const
Definition qwt_plot_rescaler.cpp:243
QwtPlotRescaler::QwtPlotRescaler
QwtPlotRescaler(QWidget *canvas, QwtAxisId referenceAxis=QwtAxis::XBottom, RescalePolicy=Expanding)
Definition qwt_plot_rescaler.cpp:71
QwtPlotRescaler::setExpandingDirection
void setExpandingDirection(ExpandingDirection)
Definition qwt_plot_rescaler.cpp:169
QwtPlotRescaler::rescalePolicy
RescalePolicy rescalePolicy() const
Definition qwt_plot_rescaler.cpp:138
QwtPlotRescaler::plot
QwtPlot * plot()
Definition qwt_plot_rescaler.cpp:294
QwtPlotRescaler::canvas
QWidget * canvas()
Definition qwt_plot_rescaler.cpp:282
QwtPlotRescaler::~QwtPlotRescaler
virtual ~QwtPlotRescaler()
Destructor.
Definition qwt_plot_rescaler.cpp:83
QwtPlotRescaler::setRescalePolicy
void setRescalePolicy(RescalePolicy)
Definition qwt_plot_rescaler.cpp:129
QwtPlotRescaler::setReferenceAxis
void setReferenceAxis(QwtAxisId)
Definition qwt_plot_rescaler.cpp:149
QwtPlotRescaler::rescale
void rescale() const
Adjust the plot axes scales.
Definition qwt_plot_rescaler.cpp:355
QwtScaleDiv
A class representing a scale division.
Definition qwt_scale_div.h:34
QwtScaleDiv::interval
QwtInterval interval() const
Definition qwt_scale_div.cpp:111
QwtScaleDiv::ticks
QList< double > ticks(int tickType) const
Definition qwt_scale_div.cpp:309
QwtScaleDiv::isIncreasing
bool isIncreasing() const
Check if the scale division is increasing( lowerBound() <= upperBound() )
Definition qwt_scale_div.cpp:201
QwtScaleDiv::NTickTypes
@ NTickTypes
Number of valid tick types.
Definition qwt_scale_div.h:52
QwtAxis
Definition qwt_axis.h:19
QwtAxis::isYAxis
bool isYAxis(int axisPos)
Definition qwt_axis.h:57
QwtAxis::XBottom
@ XBottom
X axis below the canvas.
Definition qwt_axis.h:30
QwtAxis::isValid
bool isValid(int axisPos)
Definition qwt_axis.h:45