qwt_plot_rescaler.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_plot_rescaler.h"
00011 #include "qwt_plot.h"
00012 #include "qwt_scale_div.h"
00013 #include "qwt_interval.h"
00014 #include "qwt_plot_canvas.h"
00015 #include <qevent.h>
00016 #include <qalgorithms.h>
00017 
00018 class QwtPlotRescaler::AxisData
00019 {
00020 public:
00021     AxisData():
00022         aspectRatio( 1.0 ),
00023         expandingDirection( QwtPlotRescaler::ExpandUp )
00024     {
00025     }
00026 
00027     double aspectRatio;
00028     QwtInterval intervalHint;
00029     QwtPlotRescaler::ExpandingDirection expandingDirection;
00030     mutable QwtScaleDiv scaleDiv;
00031 };
00032 
00033 class QwtPlotRescaler::PrivateData
00034 {
00035 public:
00036     PrivateData():
00037         referenceAxis( QwtPlot::xBottom ),
00038         rescalePolicy( QwtPlotRescaler::Expanding ),
00039         isEnabled( false ),
00040         inReplot( 0 )
00041     {
00042     }
00043 
00044     int referenceAxis;
00045     RescalePolicy rescalePolicy;
00046     QwtPlotRescaler::AxisData axisData[QwtPlot::axisCnt];
00047     bool isEnabled;
00048 
00049     mutable int inReplot;
00050 };
00051 
00061 QwtPlotRescaler::QwtPlotRescaler( QWidget *canvas,
00062         int referenceAxis, RescalePolicy policy ):
00063     QObject( canvas )
00064 {
00065     d_data = new PrivateData;
00066     d_data->referenceAxis = referenceAxis;
00067     d_data->rescalePolicy = policy;
00068 
00069     setEnabled( true );
00070 }
00071 
00073 QwtPlotRescaler::~QwtPlotRescaler()
00074 {
00075     delete d_data;
00076 }
00077 
00087 void QwtPlotRescaler::setEnabled( bool on )
00088 {
00089     if ( d_data->isEnabled != on )
00090     {
00091         d_data->isEnabled = on;
00092 
00093         QWidget *w = canvas();
00094         if ( w )
00095         {
00096             if ( d_data->isEnabled )
00097                 w->installEventFilter( this );
00098             else
00099                 w->removeEventFilter( this );
00100         }
00101     }
00102 }
00103 
00108 bool QwtPlotRescaler::isEnabled() const
00109 {
00110     return d_data->isEnabled;
00111 }
00112 
00119 void QwtPlotRescaler::setRescalePolicy( RescalePolicy policy )
00120 {
00121     d_data->rescalePolicy = policy;
00122 }
00123 
00128 QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const
00129 {
00130     return d_data->rescalePolicy;
00131 }
00132 
00139 void QwtPlotRescaler::setReferenceAxis( int axis )
00140 {
00141     d_data->referenceAxis = axis;
00142 }
00143 
00148 int QwtPlotRescaler::referenceAxis() const
00149 {
00150     return d_data->referenceAxis;
00151 }
00152 
00159 void QwtPlotRescaler::setExpandingDirection(
00160     ExpandingDirection direction )
00161 {
00162     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00163         setExpandingDirection( axis, direction );
00164 }
00165 
00173 void QwtPlotRescaler::setExpandingDirection(
00174     int axis, ExpandingDirection direction )
00175 {
00176     if ( axis >= 0 && axis < QwtPlot::axisCnt )
00177         d_data->axisData[axis].expandingDirection = direction;
00178 }
00179 
00186 QwtPlotRescaler::ExpandingDirection
00187 QwtPlotRescaler::expandingDirection( int axis ) const
00188 {
00189     if ( axis >= 0 && axis < QwtPlot::axisCnt )
00190         return d_data->axisData[axis].expandingDirection;
00191 
00192     return ExpandBoth;
00193 }
00194 
00202 void QwtPlotRescaler::setAspectRatio( double ratio )
00203 {
00204     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00205         setAspectRatio( axis, ratio );
00206 }
00207 
00216 void QwtPlotRescaler::setAspectRatio( int axis, double ratio )
00217 {
00218     if ( ratio < 0.0 )
00219         ratio = 0.0;
00220 
00221     if ( axis >= 0 && axis < QwtPlot::axisCnt )
00222         d_data->axisData[axis].aspectRatio = ratio;
00223 }
00224 
00231 double QwtPlotRescaler::aspectRatio( int axis ) const
00232 {
00233     if ( axis >= 0 && axis < QwtPlot::axisCnt )
00234         return d_data->axisData[axis].aspectRatio;
00235 
00236     return 0.0;
00237 }
00238 
00249 void QwtPlotRescaler::setIntervalHint( int axis,
00250     const QwtInterval &interval )
00251 {
00252     if ( axis >= 0 && axis < QwtPlot::axisCnt )
00253         d_data->axisData[axis].intervalHint = interval;
00254 }
00255 
00261 QwtInterval QwtPlotRescaler::intervalHint( int axis ) const
00262 {
00263     if ( axis >= 0 && axis < QwtPlot::axisCnt )
00264         return d_data->axisData[axis].intervalHint;
00265 
00266     return QwtInterval();
00267 }
00268 
00270 QWidget *QwtPlotRescaler::canvas()
00271 {
00272     return qobject_cast<QWidget *>( parent() );
00273 }
00274 
00276 const QWidget *QwtPlotRescaler::canvas() const
00277 {
00278     return qobject_cast<const QWidget *>( parent() );
00279 }
00280 
00282 QwtPlot *QwtPlotRescaler::plot()
00283 {
00284     QWidget *w = canvas();
00285     if ( w )
00286         w = w->parentWidget();
00287 
00288     return qobject_cast<QwtPlot *>( w );
00289 }
00290 
00292 const QwtPlot *QwtPlotRescaler::plot() const
00293 {
00294     const QWidget *w = canvas();
00295     if ( w )
00296         w = w->parentWidget();
00297 
00298     return qobject_cast<const QwtPlot *>( w );
00299 }
00300 
00302 bool QwtPlotRescaler::eventFilter( QObject *object, QEvent *event )
00303 {
00304     if ( object && object == canvas() )
00305     {
00306         switch ( event->type() )
00307         {
00308             case QEvent::Resize:
00309             {
00310                 canvasResizeEvent( static_cast<QResizeEvent *>( event ) );
00311                 break;
00312             }
00313             case QEvent::PolishRequest:
00314             {
00315                 rescale();
00316                 break;
00317             }
00318             default:;
00319         }
00320     }
00321 
00322     return false;
00323 }
00324 
00331 void QwtPlotRescaler::canvasResizeEvent( QResizeEvent* event )
00332 {
00333     int left, top, right, bottom;
00334     canvas()->getContentsMargins( &left, &top, &right, &bottom );
00335 
00336     const QSize marginSize( left + right, top + bottom );
00337 
00338     const QSize newSize = event->size() - marginSize;
00339     const QSize oldSize = event->oldSize() - marginSize;
00340 
00341     rescale( oldSize, newSize );
00342 }
00343 
00345 void QwtPlotRescaler::rescale() const
00346 {
00347     const QSize size = canvas()->contentsRect().size();
00348     rescale( size, size );
00349 }
00350 
00357 void QwtPlotRescaler::rescale(
00358     const QSize &oldSize, const QSize &newSize ) const
00359 {
00360     if ( newSize.isEmpty() )
00361         return;
00362 
00363     QwtInterval intervals[QwtPlot::axisCnt];
00364     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00365         intervals[axis] = interval( axis );
00366 
00367     const int refAxis = referenceAxis();
00368     intervals[refAxis] = expandScale( refAxis, oldSize, newSize );
00369 
00370     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00371     {
00372         if ( aspectRatio( axis ) > 0.0 && axis != refAxis )
00373             intervals[axis] = syncScale( axis, intervals[refAxis], newSize );
00374     }
00375 
00376     updateScales( intervals );
00377 }
00378 
00388 QwtInterval QwtPlotRescaler::expandScale( int axis,
00389         const QSize &oldSize, const QSize &newSize ) const
00390 {
00391     const QwtInterval oldInterval = interval( axis );
00392 
00393     QwtInterval expanded = oldInterval;
00394     switch ( rescalePolicy() )
00395     {
00396         case Fixed:
00397         {
00398             break; // do nothing
00399         }
00400         case Expanding:
00401         {
00402             if ( !oldSize.isEmpty() )
00403             {
00404                 double width = oldInterval.width();
00405                 if ( orientation( axis ) == Qt::Horizontal )
00406                     width *= double( newSize.width() ) / oldSize.width();
00407                 else
00408                     width *= double( newSize.height() ) / oldSize.height();
00409 
00410                 expanded = expandInterval( oldInterval,
00411                     width, expandingDirection( axis ) );
00412             }
00413             break;
00414         }
00415         case Fitting:
00416         {
00417             double dist = 0.0;
00418             for ( int ax = 0; ax < QwtPlot::axisCnt; ax++ )
00419             {
00420                 const double d = pixelDist( ax, newSize );
00421                 if ( d > dist )
00422                     dist = d;
00423             }
00424             if ( dist > 0.0 )
00425             {
00426                 double width;
00427                 if ( orientation( axis ) == Qt::Horizontal )
00428                     width = newSize.width() * dist;
00429                 else
00430                     width = newSize.height() * dist;
00431 
00432                 expanded = expandInterval( intervalHint( axis ),
00433                     width, expandingDirection( axis ) );
00434             }
00435             break;
00436         }
00437     }
00438 
00439     return expanded;
00440 }
00441 
00451 QwtInterval QwtPlotRescaler::syncScale( int axis,
00452     const QwtInterval& reference, const QSize &size ) const
00453 {
00454     double dist;
00455     if ( orientation( referenceAxis() ) == Qt::Horizontal )
00456         dist = reference.width() / size.width();
00457     else
00458         dist = reference.width() / size.height();
00459 
00460     if ( orientation( axis ) == Qt::Horizontal )
00461         dist *= size.width();
00462     else
00463         dist *= size.height();
00464 
00465     dist /= aspectRatio( axis );
00466 
00467     QwtInterval intv;
00468     if ( rescalePolicy() == Fitting )
00469         intv = intervalHint( axis );
00470     else
00471         intv = interval( axis );
00472 
00473     intv = expandInterval( intv, dist, expandingDirection( axis ) );
00474 
00475     return intv;
00476 }
00477 
00482 Qt::Orientation QwtPlotRescaler::orientation( int axis ) const
00483 {
00484     if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight )
00485         return Qt::Vertical;
00486 
00487     return Qt::Horizontal;
00488 }
00489 
00494 QwtInterval QwtPlotRescaler::interval( int axis ) const
00495 {
00496     if ( axis < 0 || axis >= QwtPlot::axisCnt )
00497         return QwtInterval();
00498 
00499     return plot()->axisScaleDiv( axis ).interval().normalized();
00500 }
00501 
00511 QwtInterval QwtPlotRescaler::expandInterval(
00512     const QwtInterval &interval, double width,
00513     ExpandingDirection direction ) const
00514 {
00515     QwtInterval expanded = interval;
00516 
00517     switch ( direction )
00518     {
00519         case ExpandUp:
00520             expanded.setMinValue( interval.minValue() );
00521             expanded.setMaxValue( interval.minValue() + width );
00522             break;
00523 
00524         case ExpandDown:
00525             expanded.setMaxValue( interval.maxValue() );
00526             expanded.setMinValue( interval.maxValue() - width );
00527             break;
00528 
00529         case ExpandBoth:
00530         default:
00531             expanded.setMinValue( interval.minValue() +
00532                 interval.width() / 2.0 - width / 2.0 );
00533             expanded.setMaxValue( expanded.minValue() + width );
00534     }
00535     return expanded;
00536 }
00537 
00538 double QwtPlotRescaler::pixelDist( int axis, const QSize &size ) const
00539 {
00540     const QwtInterval intv = intervalHint( axis );
00541 
00542     double dist = 0.0;
00543     if ( !intv.isNull() )
00544     {
00545         if ( axis == referenceAxis() )
00546             dist = intv.width();
00547         else
00548         {
00549             const double r = aspectRatio( axis );
00550             if ( r > 0.0 )
00551                 dist = intv.width() * r;
00552         }
00553     }
00554 
00555     if ( dist > 0.0 )
00556     {
00557         if ( orientation( axis ) == Qt::Horizontal )
00558             dist /= size.width();
00559         else
00560             dist /= size.height();
00561     }
00562 
00563     return dist;
00564 }
00565 
00571 void QwtPlotRescaler::updateScales(
00572     QwtInterval intervals[QwtPlot::axisCnt] ) const
00573 {
00574     if ( d_data->inReplot >= 5 )
00575     {
00576         return;
00577     }
00578 
00579     QwtPlot *plt = const_cast<QwtPlot *>( plot() );
00580 
00581     const bool doReplot = plt->autoReplot();
00582     plt->setAutoReplot( false );
00583 
00584     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00585     {
00586         if ( axis == referenceAxis() || aspectRatio( axis ) > 0.0 )
00587         {
00588             double v1 = intervals[axis].minValue();
00589             double v2 = intervals[axis].maxValue();
00590 
00591             if ( !plt->axisScaleDiv( axis ).isIncreasing() )
00592                 qSwap( v1, v2 );
00593 
00594             if ( d_data->inReplot >= 1 )
00595                 d_data->axisData[axis].scaleDiv = plt->axisScaleDiv( axis );
00596 
00597             if ( d_data->inReplot >= 2 )
00598             {
00599                 QList<double> ticks[QwtScaleDiv::NTickTypes];
00600                 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
00601                     ticks[i] = d_data->axisData[axis].scaleDiv.ticks( i );
00602 
00603                 plt->setAxisScaleDiv( axis, QwtScaleDiv( v1, v2, ticks ) );
00604             }
00605             else
00606             {
00607                 plt->setAxisScale( axis, v1, v2 );
00608             }
00609         }
00610     }
00611 
00612     QwtPlotCanvas *canvas = qobject_cast<QwtPlotCanvas *>( plt->canvas() );
00613 
00614     bool immediatePaint = false;
00615     if ( canvas )
00616     {
00617         immediatePaint = canvas->testPaintAttribute( QwtPlotCanvas::ImmediatePaint );
00618         canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false );
00619     }
00620 
00621     plt->setAutoReplot( doReplot );
00622 
00623     d_data->inReplot++;
00624     plt->replot();
00625     d_data->inReplot--;
00626 
00627     if ( canvas && immediatePaint )
00628     {
00629         canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true );
00630     }
00631 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56