qwt_plot_zoomer.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_zoomer.h"
00011 #include "qwt_plot.h"
00012 #include "qwt_scale_div.h"
00013 #include "qwt_picker_machine.h"
00014 #include <qalgorithms.h>
00015 
00016 static QwtInterval qwtExpandedZoomInterval( double v1, double v2, 
00017     double minRange, const QwtTransform* transform )
00018 {
00019     double min = v1;
00020     double max = v2;
00021 
00022     if ( max - min < minRange )
00023     {
00024         min = 0.5 * ( min + max - minRange );
00025         max = min + minRange;
00026 
00027         if ( transform )
00028         {
00029             // f.e the logarithmic scale doesn't allow values
00030             // outside [QwtLogTransform::LogMin/QwtLogTransform::LogMax]
00031 
00032             double minBounded = transform->bounded( min );
00033             double maxBounded = transform->bounded( max );
00034 
00035             if ( minBounded != min )
00036             {
00037                 maxBounded = transform->bounded( minBounded + minRange );
00038             }
00039             else if ( maxBounded != max )
00040             {
00041                 minBounded = transform->bounded( maxBounded - minRange );
00042             }
00043 
00044             min = minBounded;
00045             max = maxBounded;
00046         }
00047     }
00048 
00049     return QwtInterval( min, max );
00050 }
00051 
00052 static QRectF qwtExpandedZoomRect( const QRectF &zoomRect, const QSizeF &minSize,
00053     const QwtTransform* transformX, const QwtTransform* transformY )
00054 {
00055     QRectF r = zoomRect;
00056 
00057     if ( minSize.width() > r.width() )
00058     {
00059         const QwtInterval intv = qwtExpandedZoomInterval(
00060             r.left(), r.right(), minSize.width(), transformX );
00061 
00062         r.setLeft( intv.minValue() );
00063         r.setRight( intv.maxValue() );
00064     }
00065 
00066     if ( minSize.height() > r.height() )
00067     {
00068         const QwtInterval intv = qwtExpandedZoomInterval(
00069             zoomRect.top(), zoomRect.bottom(), minSize.height(), transformY );
00070 
00071         r.setTop( intv.minValue() );
00072         r.setBottom( intv.maxValue() );
00073     }
00074 
00075     return r;
00076 }
00077 
00078 class QwtPlotZoomer::PrivateData
00079 {
00080 public:
00081     uint zoomRectIndex;
00082     QStack<QRectF> zoomStack;
00083 
00084     int maxStackDepth;
00085 };
00086 
00106 QwtPlotZoomer::QwtPlotZoomer( QWidget *canvas, bool doReplot ):
00107     QwtPlotPicker( canvas )
00108 {
00109     if ( canvas )
00110         init( doReplot );
00111 }
00112 
00130 QwtPlotZoomer::QwtPlotZoomer( int xAxis, int yAxis,
00131         QWidget *canvas, bool doReplot ):
00132     QwtPlotPicker( xAxis, yAxis, canvas )
00133 {
00134     if ( canvas )
00135         init( doReplot );
00136 }
00137 
00139 void QwtPlotZoomer::init( bool doReplot )
00140 {
00141     d_data = new PrivateData;
00142 
00143     d_data->maxStackDepth = -1;
00144 
00145     setTrackerMode( ActiveOnly );
00146     setRubberBand( RectRubberBand );
00147     setStateMachine( new QwtPickerDragRectMachine() );
00148 
00149     if ( doReplot && plot() )
00150         plot()->replot();
00151 
00152     setZoomBase( scaleRect() );
00153 }
00154 
00155 QwtPlotZoomer::~QwtPlotZoomer()
00156 {
00157     delete d_data;
00158 }
00159 
00171 void QwtPlotZoomer::setMaxStackDepth( int depth )
00172 {
00173     d_data->maxStackDepth = depth;
00174 
00175     if ( depth >= 0 )
00176     {
00177         // unzoom if the current depth is below d_data->maxStackDepth
00178 
00179         const int zoomOut =
00180             int( d_data->zoomStack.count() ) - 1 - depth; // -1 for the zoom base
00181 
00182         if ( zoomOut > 0 )
00183         {
00184             zoom( -zoomOut );
00185             for ( int i = int( d_data->zoomStack.count() ) - 1;
00186                 i > int( d_data->zoomRectIndex ); i-- )
00187             {
00188                 ( void )d_data->zoomStack.pop(); // remove trailing rects
00189             }
00190         }
00191     }
00192 }
00193 
00198 int QwtPlotZoomer::maxStackDepth() const
00199 {
00200     return d_data->maxStackDepth;
00201 }
00202 
00209 const QStack<QRectF> &QwtPlotZoomer::zoomStack() const
00210 {
00211     return d_data->zoomStack;
00212 }
00213 
00218 QRectF QwtPlotZoomer::zoomBase() const
00219 {
00220     return d_data->zoomStack[0];
00221 }
00222 
00232 void QwtPlotZoomer::setZoomBase( bool doReplot )
00233 {
00234     QwtPlot *plt = plot();
00235     if ( plt == NULL )
00236         return;
00237 
00238     if ( doReplot )
00239         plt->replot();
00240 
00241     d_data->zoomStack.clear();
00242     d_data->zoomStack.push( scaleRect() );
00243     d_data->zoomRectIndex = 0;
00244 
00245     rescale();
00246 }
00247 
00258 void QwtPlotZoomer::setZoomBase( const QRectF &base )
00259 {
00260     const QwtPlot *plt = plot();
00261     if ( !plt )
00262         return;
00263 
00264     const QRectF sRect = scaleRect();
00265     const QRectF bRect = base | sRect;
00266 
00267     d_data->zoomStack.clear();
00268     d_data->zoomStack.push( bRect );
00269     d_data->zoomRectIndex = 0;
00270 
00271     if ( base != sRect )
00272     {
00273         d_data->zoomStack.push( sRect );
00274         d_data->zoomRectIndex++;
00275     }
00276 
00277     rescale();
00278 }
00279 
00284 QRectF QwtPlotZoomer::zoomRect() const
00285 {
00286     return d_data->zoomStack[d_data->zoomRectIndex];
00287 }
00288 
00292 uint QwtPlotZoomer::zoomRectIndex() const
00293 {
00294     return d_data->zoomRectIndex;
00295 }
00296 
00307 void QwtPlotZoomer::zoom( const QRectF &rect )
00308 {
00309     if ( d_data->maxStackDepth >= 0 &&
00310             int( d_data->zoomRectIndex ) >= d_data->maxStackDepth )
00311     {
00312         return;
00313     }
00314 
00315     const QRectF zoomRect = rect.normalized();
00316     if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
00317     {
00318         for ( uint i = int( d_data->zoomStack.count() ) - 1;
00319            i > d_data->zoomRectIndex; i-- )
00320         {
00321             ( void )d_data->zoomStack.pop();
00322         }
00323 
00324         d_data->zoomStack.push( zoomRect );
00325         d_data->zoomRectIndex++;
00326 
00327         rescale();
00328 
00329         Q_EMIT zoomed( zoomRect );
00330     }
00331 }
00332 
00344 void QwtPlotZoomer::zoom( int offset )
00345 {
00346     int newIndex;
00347 
00348     if ( offset == 0 )
00349     {
00350         newIndex = 0;
00351     }
00352     else
00353     {
00354         newIndex = d_data->zoomRectIndex + offset;
00355         newIndex = qBound( 0, newIndex, d_data->zoomStack.count() - 1 );
00356     }
00357 
00358     if ( newIndex != static_cast<int>( d_data->zoomRectIndex ) )
00359     {
00360         d_data->zoomRectIndex = newIndex;
00361         rescale();
00362         Q_EMIT zoomed( zoomRect() );
00363     }
00364 }
00365 
00380 void QwtPlotZoomer::setZoomStack(
00381     const QStack<QRectF> &zoomStack, int zoomRectIndex )
00382 {
00383     if ( zoomStack.isEmpty() )
00384         return;
00385 
00386     if ( d_data->maxStackDepth >= 0 &&
00387         int( zoomStack.count() ) > d_data->maxStackDepth )
00388     {
00389         return;
00390     }
00391 
00392     if ( zoomRectIndex < 0 || zoomRectIndex > int( zoomStack.count() ) )
00393         zoomRectIndex = zoomStack.count() - 1;
00394 
00395     const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();
00396 
00397     d_data->zoomStack = zoomStack;
00398     d_data->zoomRectIndex = uint( zoomRectIndex );
00399 
00400     if ( doRescale )
00401     {
00402         rescale();
00403         Q_EMIT zoomed( zoomRect() );
00404     }
00405 }
00406 
00413 void QwtPlotZoomer::rescale()
00414 {
00415     QwtPlot *plt = plot();
00416     if ( !plt )
00417         return;
00418 
00419     const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
00420     if ( rect != scaleRect() )
00421     {
00422         const bool doReplot = plt->autoReplot();
00423         plt->setAutoReplot( false );
00424 
00425         double x1 = rect.left();
00426         double x2 = rect.right();
00427         if ( !plt->axisScaleDiv( xAxis() ).isIncreasing() )
00428             qSwap( x1, x2 );
00429 
00430         plt->setAxisScale( xAxis(), x1, x2 );
00431 
00432         double y1 = rect.top();
00433         double y2 = rect.bottom();
00434         if ( !plt->axisScaleDiv( yAxis() ).isIncreasing() )
00435             qSwap( y1, y2 );
00436 
00437         plt->setAxisScale( yAxis(), y1, y2 );
00438 
00439         plt->setAutoReplot( doReplot );
00440 
00441         plt->replot();
00442     }
00443 }
00444 
00452 void QwtPlotZoomer::setAxis( int xAxis, int yAxis )
00453 {
00454     if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00455     {
00456         QwtPlotPicker::setAxis( xAxis, yAxis );
00457         setZoomBase( scaleRect() );
00458     }
00459 }
00460 
00471 void QwtPlotZoomer::widgetMouseReleaseEvent( QMouseEvent *me )
00472 {
00473     if ( mouseMatch( MouseSelect2, me ) )
00474         zoom( 0 );
00475     else if ( mouseMatch( MouseSelect3, me ) )
00476         zoom( -1 );
00477     else if ( mouseMatch( MouseSelect6, me ) )
00478         zoom( +1 );
00479     else
00480         QwtPlotPicker::widgetMouseReleaseEvent( me );
00481 }
00482 
00494 void QwtPlotZoomer::widgetKeyPressEvent( QKeyEvent *ke )
00495 {
00496     if ( !isActive() )
00497     {
00498         if ( keyMatch( KeyUndo, ke ) )
00499             zoom( -1 );
00500         else if ( keyMatch( KeyRedo, ke ) )
00501             zoom( +1 );
00502         else if ( keyMatch( KeyHome, ke ) )
00503             zoom( 0 );
00504     }
00505 
00506     QwtPlotPicker::widgetKeyPressEvent( ke );
00507 }
00508 
00517 void QwtPlotZoomer::moveBy( double dx, double dy )
00518 {
00519     const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
00520     moveTo( QPointF( rect.left() + dx, rect.top() + dy ) );
00521 }
00522 
00531 void QwtPlotZoomer::moveTo( const QPointF &pos )
00532 {
00533     double x = pos.x();
00534     double y = pos.y();
00535 
00536     if ( x < zoomBase().left() )
00537         x = zoomBase().left();
00538     if ( x > zoomBase().right() - zoomRect().width() )
00539         x = zoomBase().right() - zoomRect().width();
00540 
00541     if ( y < zoomBase().top() )
00542         y = zoomBase().top();
00543     if ( y > zoomBase().bottom() - zoomRect().height() )
00544         y = zoomBase().bottom() - zoomRect().height();
00545 
00546     if ( x != zoomRect().left() || y != zoomRect().top() )
00547     {
00548         d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y );
00549         rescale();
00550     }
00551 }
00552 
00564 bool QwtPlotZoomer::accept( QPolygon &pa ) const
00565 {
00566     if ( pa.count() < 2 )
00567         return false;
00568 
00569     QRect rect = QRect( pa[0], pa[int( pa.count() ) - 1] );
00570     rect = rect.normalized();
00571 
00572     const int minSize = 2;
00573     if ( rect.width() < minSize && rect.height() < minSize )
00574         return false;
00575 
00576     const int minZoomSize = 11;
00577 
00578     const QPoint center = rect.center();
00579     rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) );
00580     rect.moveCenter( center );
00581 
00582     pa.resize( 2 );
00583     pa[0] = rect.topLeft();
00584     pa[1] = rect.bottomRight();
00585 
00586     return true;
00587 }
00588 
00594 QSizeF QwtPlotZoomer::minZoomSize() const
00595 {
00596     return QSizeF( d_data->zoomStack[0].width() / 10e4,
00597         d_data->zoomStack[0].height() / 10e4 );
00598 }
00599 
00606 void QwtPlotZoomer::begin()
00607 {
00608     if ( d_data->maxStackDepth >= 0 )
00609     {
00610         if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) )
00611             return;
00612     }
00613 
00614     const QSizeF minSize = minZoomSize();
00615     if ( minSize.isValid() )
00616     {
00617         const QSizeF sz =
00618             d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00619 
00620         if ( minSize.width() >= sz.width() &&
00621             minSize.height() >= sz.height() )
00622         {
00623             return;
00624         }
00625     }
00626 
00627     QwtPlotPicker::begin();
00628 }
00629 
00640 bool QwtPlotZoomer::end( bool ok )
00641 {
00642     ok = QwtPlotPicker::end( ok );
00643     if ( !ok )
00644         return false;
00645 
00646     QwtPlot *plot = QwtPlotZoomer::plot();
00647     if ( !plot )
00648         return false;
00649 
00650     const QPolygon &pa = selection();
00651     if ( pa.count() < 2 )
00652         return false;
00653 
00654     QRect rect = QRect( pa[0], pa[int( pa.count() - 1 )] );
00655     rect = rect.normalized();
00656 
00657     const QwtScaleMap xMap = plot->canvasMap( xAxis() );
00658     const QwtScaleMap yMap = plot->canvasMap( yAxis() );
00659 
00660     QRectF zoomRect = QwtScaleMap::invTransform( xMap, yMap, rect ).normalized();
00661 
00662     zoomRect = qwtExpandedZoomRect( zoomRect, minZoomSize(),
00663         xMap.transformation(), yMap.transformation() );
00664 
00665     zoom( zoomRect );
00666 
00667     return true;
00668 }


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