qwt_plot_zoomer.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_plot_zoomer.h"
11 #include "qwt_plot.h"
12 #include "qwt_scale_div.h"
13 #include "qwt_scale_map.h"
14 #include "qwt_interval.h"
15 #include "qwt_picker_machine.h"
16 
17 #include <qstack.h>
18 
19 static QwtInterval qwtExpandedZoomInterval( double v1, double v2,
20  double minRange, const QwtTransform* transform )
21 {
22  double min = v1;
23  double max = v2;
24 
25  if ( max - min < minRange )
26  {
27  min = 0.5 * ( min + max - minRange );
28  max = min + minRange;
29 
30  if ( transform )
31  {
32  // f.e the logarithmic scale doesn't allow values
33  // outside [QwtLogTransform::LogMin/QwtLogTransform::LogMax]
34 
35  double minBounded = transform->bounded( min );
36  double maxBounded = transform->bounded( max );
37 
38  if ( minBounded != min )
39  {
40  maxBounded = transform->bounded( minBounded + minRange );
41  }
42  else if ( maxBounded != max )
43  {
44  minBounded = transform->bounded( maxBounded - minRange );
45  }
46 
47  min = minBounded;
48  max = maxBounded;
49  }
50  }
51 
52  return QwtInterval( min, max );
53 }
54 
55 static QRectF qwtExpandedZoomRect( const QRectF &zoomRect, const QSizeF &minSize,
56  const QwtTransform* transformX, const QwtTransform* transformY )
57 {
58  QRectF r = zoomRect;
59 
60  if ( minSize.width() > r.width() )
61  {
63  r.left(), r.right(), minSize.width(), transformX );
64 
65  r.setLeft( intv.minValue() );
66  r.setRight( intv.maxValue() );
67  }
68 
69  if ( minSize.height() > r.height() )
70  {
72  zoomRect.top(), zoomRect.bottom(), minSize.height(), transformY );
73 
74  r.setTop( intv.minValue() );
75  r.setBottom( intv.maxValue() );
76  }
77 
78  return r;
79 }
80 
82 {
83 public:
86 
88 };
89 
109 QwtPlotZoomer::QwtPlotZoomer( QWidget *canvas, bool doReplot ):
110  QwtPlotPicker( canvas )
111 {
112  if ( canvas )
113  init( doReplot );
114 }
115 
134  QWidget *canvas, bool doReplot ):
135  QwtPlotPicker( xAxis, yAxis, canvas )
136 {
137  if ( canvas )
138  init( doReplot );
139 }
140 
142 void QwtPlotZoomer::init( bool doReplot )
143 {
144  d_data = new PrivateData;
145 
146  d_data->maxStackDepth = -1;
147 
151 
152  if ( doReplot && plot() )
153  plot()->replot();
154 
155  setZoomBase( scaleRect() );
156 }
157 
159 {
160  delete d_data;
161 }
162 
175 {
176  d_data->maxStackDepth = depth;
177 
178  if ( depth >= 0 )
179  {
180  // unzoom if the current depth is below d_data->maxStackDepth
181 
182  const int zoomOut =
183  d_data->zoomStack.count() - 1 - depth; // -1 for the zoom base
184 
185  if ( zoomOut > 0 )
186  {
187  zoom( -zoomOut );
188  for ( int i = d_data->zoomStack.count() - 1;
189  i > int( d_data->zoomRectIndex ); i-- )
190  {
191  ( void )d_data->zoomStack.pop(); // remove trailing rects
192  }
193  }
194  }
195 }
196 
202 {
203  return d_data->maxStackDepth;
204 }
205 
213 {
214  return d_data->zoomStack;
215 }
216 
222 {
223  return d_data->zoomStack[0];
224 }
225 
235 void QwtPlotZoomer::setZoomBase( bool doReplot )
236 {
237  QwtPlot *plt = plot();
238  if ( plt == NULL )
239  return;
240 
241  if ( doReplot )
242  plt->replot();
243 
244  d_data->zoomStack.clear();
245  d_data->zoomStack.push( scaleRect() );
246  d_data->zoomRectIndex = 0;
247 
248  rescale();
249 }
250 
261 void QwtPlotZoomer::setZoomBase( const QRectF &base )
262 {
263  const QwtPlot *plt = plot();
264  if ( !plt )
265  return;
266 
267  const QRectF sRect = scaleRect();
268  const QRectF bRect = base | sRect;
269 
270  d_data->zoomStack.clear();
271  d_data->zoomStack.push( bRect );
272  d_data->zoomRectIndex = 0;
273 
274  if ( base != sRect )
275  {
276  d_data->zoomStack.push( sRect );
278  }
279 
280  rescale();
281 }
282 
288 {
290 }
291 
296 {
297  return d_data->zoomRectIndex;
298 }
299 
310 void QwtPlotZoomer::zoom( const QRectF &rect )
311 {
312  if ( d_data->maxStackDepth >= 0 &&
314  {
315  return;
316  }
317 
318  const QRectF zoomRect = rect.normalized();
319  if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
320  {
321  for ( uint i = d_data->zoomStack.count() - 1;
322  i > d_data->zoomRectIndex; i-- )
323  {
324  ( void )d_data->zoomStack.pop();
325  }
326 
327  d_data->zoomStack.push( zoomRect );
329 
330  rescale();
331 
332  Q_EMIT zoomed( zoomRect );
333  }
334 }
335 
347 void QwtPlotZoomer::zoom( int offset )
348 {
349  int newIndex;
350 
351  if ( offset == 0 )
352  {
353  newIndex = 0;
354  }
355  else
356  {
357  newIndex = d_data->zoomRectIndex + offset;
358  newIndex = qBound( 0, newIndex, d_data->zoomStack.count() - 1 );
359  }
360 
361  if ( newIndex != static_cast<int>( d_data->zoomRectIndex ) )
362  {
363  d_data->zoomRectIndex = newIndex;
364  rescale();
365  Q_EMIT zoomed( zoomRect() );
366  }
367 }
368 
385 {
386  if ( zoomStack.isEmpty() )
387  return;
388 
389  if ( d_data->maxStackDepth >= 0 &&
390  zoomStack.count() > d_data->maxStackDepth )
391  {
392  return;
393  }
394 
395  if ( zoomRectIndex < 0 || zoomRectIndex > zoomStack.count() )
396  zoomRectIndex = zoomStack.count() - 1;
397 
398  const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();
399 
401  d_data->zoomRectIndex = uint( zoomRectIndex );
402 
403  if ( doRescale )
404  {
405  rescale();
406  Q_EMIT zoomed( zoomRect() );
407  }
408 }
409 
417 {
418  QwtPlot *plt = plot();
419  if ( !plt )
420  return;
421 
422  const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
423  if ( rect != scaleRect() )
424  {
425  const bool doReplot = plt->autoReplot();
426  plt->setAutoReplot( false );
427 
428  double x1 = rect.left();
429  double x2 = rect.right();
430  if ( !plt->axisScaleDiv( xAxis() ).isIncreasing() )
431  qSwap( x1, x2 );
432 
433  plt->setAxisScale( xAxis(), x1, x2 );
434 
435  double y1 = rect.top();
436  double y2 = rect.bottom();
437  if ( !plt->axisScaleDiv( yAxis() ).isIncreasing() )
438  qSwap( y1, y2 );
439 
440  plt->setAxisScale( yAxis(), y1, y2 );
441 
442  plt->setAutoReplot( doReplot );
443 
444  plt->replot();
445  }
446 }
447 
456 {
457  if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
458  {
459  QwtPlotPicker::setAxis( xAxis, yAxis );
460  setZoomBase( scaleRect() );
461  }
462 }
463 
475 {
476  if ( mouseMatch( MouseSelect2, me ) )
477  zoom( 0 );
478  else if ( mouseMatch( MouseSelect3, me ) )
479  zoom( -1 );
480  else if ( mouseMatch( MouseSelect6, me ) )
481  zoom( +1 );
482  else
484 }
485 
498 {
499  if ( !isActive() )
500  {
501  if ( keyMatch( KeyUndo, ke ) )
502  zoom( -1 );
503  else if ( keyMatch( KeyRedo, ke ) )
504  zoom( +1 );
505  else if ( keyMatch( KeyHome, ke ) )
506  zoom( 0 );
507  }
508 
510 }
511 
520 void QwtPlotZoomer::moveBy( double dx, double dy )
521 {
522  const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
523  moveTo( QPointF( rect.left() + dx, rect.top() + dy ) );
524 }
525 
534 void QwtPlotZoomer::moveTo( const QPointF &pos )
535 {
536  double x = pos.x();
537  double y = pos.y();
538 
539  if ( x < zoomBase().left() )
540  x = zoomBase().left();
541  if ( x > zoomBase().right() - zoomRect().width() )
542  x = zoomBase().right() - zoomRect().width();
543 
544  if ( y < zoomBase().top() )
545  y = zoomBase().top();
546  if ( y > zoomBase().bottom() - zoomRect().height() )
547  y = zoomBase().bottom() - zoomRect().height();
548 
549  if ( x != zoomRect().left() || y != zoomRect().top() )
550  {
551  d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y );
552  rescale();
553  }
554 }
555 
567 bool QwtPlotZoomer::accept( QPolygon &pa ) const
568 {
569  if ( pa.count() < 2 )
570  return false;
571 
572  QRect rect = QRect( pa.first(), pa.last() );
573  rect = rect.normalized();
574 
575  const int minSize = 2;
576  if ( rect.width() < minSize && rect.height() < minSize )
577  return false;
578 
579  const int minZoomSize = 11;
580 
581  const QPoint center = rect.center();
582  rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) );
583  rect.moveCenter( center );
584 
585  pa.resize( 2 );
586  pa[0] = rect.topLeft();
587  pa[1] = rect.bottomRight();
588 
589  return true;
590 }
591 
598 {
599  return QSizeF( d_data->zoomStack[0].width() / 10e4,
600  d_data->zoomStack[0].height() / 10e4 );
601 }
602 
610 {
611  if ( d_data->maxStackDepth >= 0 )
612  {
613  if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) )
614  return;
615  }
616 
617  const QSizeF minSize = minZoomSize();
618  if ( minSize.isValid() )
619  {
620  const QSizeF sz =
621  d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
622 
623  if ( minSize.width() >= sz.width() &&
624  minSize.height() >= sz.height() )
625  {
626  return;
627  }
628  }
629 
631 }
632 
643 bool QwtPlotZoomer::end( bool ok )
644 {
645  ok = QwtPlotPicker::end( ok );
646  if ( !ok )
647  return false;
648 
650  if ( !plot )
651  return false;
652 
653  const QPolygon &pa = selection();
654  if ( pa.count() < 2 )
655  return false;
656 
657  QRect rect = QRect( pa.first(), pa.last() );
658  rect = rect.normalized();
659 
660  const QwtScaleMap xMap = plot->canvasMap( xAxis() );
661  const QwtScaleMap yMap = plot->canvasMap( yAxis() );
662 
663  QRectF zoomRect = QwtScaleMap::invTransform( xMap, yMap, rect ).normalized();
664 
665  zoomRect = qwtExpandedZoomRect( zoomRect, minZoomSize(),
666  xMap.transformation(), yMap.transformation() );
667 
668  zoom( zoomRect );
669 
670  return true;
671 }
int yAxis() const
Return y axis.
virtual void widgetKeyPressEvent(QKeyEvent *)
QwtPlotZoomer(QWidget *, bool doReplot=true)
Create a zoomer for a plot canvas.
void setZoomStack(const QStack< QRectF > &, int zoomRectIndex=-1)
Assign a zoom stack.
virtual void zoom(const QRectF &)
Zoom in.
const QwtScaleDiv & axisScaleDiv(int axisId) const
Return the scale division of a specified axis.
void setRubberBand(RubberBand)
Definition: qwt_picker.cpp:301
QRectF zoomBase() const
uint zoomRectIndex() const
A class representing an interval.
Definition: qwt_interval.h:26
virtual void rescale()
const QStack< QRectF > & zoomStack() const
QWidget * canvas()
double minValue() const
Definition: qwt_interval.h:193
void setTrackerMode(DisplayMode)
Set the display mode of the tracker.
Definition: qwt_picker.cpp:331
QRectF scaleRect() const
void setAutoReplot(bool=true)
Set or reset the autoReplot option.
Definition: qwt_plot.cpp:314
virtual bool end(bool ok=true)
virtual QSizeF minZoomSize() const
Limit zooming by a minimum rectangle.
QwtPlot * plot()
virtual void replot()
Redraw the plot.
Definition: qwt_plot.cpp:546
A 2-D plotting widget.
Definition: qwt_plot.h:74
QPolygon selection() const
Definition: qwt_picker.cpp:801
virtual void widgetKeyPressEvent(QKeyEvent *) override
TFSIMD_FORCE_INLINE const tfScalar & y() const
QRectF zoomRect() const
virtual void setAxis(int xAxis, int yAxis)
double maxValue() const
Definition: qwt_interval.h:199
virtual void setAxis(int xAxis, int yAxis) override
bool isActive() const
virtual bool end(bool ok=true) override
virtual double bounded(double value) const
A state machine for rectangle selections.
bool autoReplot
Definition: qwt_plot.h:80
void setStateMachine(QwtPickerMachine *)
Definition: qwt_picker.cpp:241
A transformation between coordinate systems.
Definition: qwt_transform.h:35
virtual QwtScaleMap canvasMap(int axisId) const
Definition: qwt_plot.cpp:790
PrivateData * d_data
TFSIMD_FORCE_INLINE const tfScalar & x() const
QwtPlotPicker provides selections on a plot canvas.
const QwtTransform * transformation() const
Get the transformation.
A scale map.
Definition: qwt_scale_map.h:30
double invTransform(double p) const
bool mouseMatch(MousePatternCode, const QMouseEvent *) const
Compare a mouse event with an event pattern.
int maxStackDepth() const
void setMaxStackDepth(int)
Limit the number of recursive zoom operations to depth.
bool isIncreasing() const
Check if the scale division is increasing( lowerBound() <= upperBound() )
void moveBy(double dx, double dy)
virtual ~QwtPlotZoomer()
static QRectF qwtExpandedZoomRect(const QRectF &zoomRect, const QSizeF &minSize, const QwtTransform *transformX, const QwtTransform *transformY)
int xAxis() const
Return x axis.
virtual void setZoomBase(bool doReplot=true)
A rectangle ( only for QwtPickerMachine::RectSelection )
Definition: qwt_picker.h:134
virtual void widgetMouseReleaseEvent(QMouseEvent *) override
int min(int a, int b)
static QwtInterval qwtExpandedZoomInterval(double v1, double v2, double minRange, const QwtTransform *transform)
virtual void widgetMouseReleaseEvent(QMouseEvent *)
bool keyMatch(KeyPatternCode, const QKeyEvent *) const
Compare a key event with an event pattern.
void init(bool doReplot)
Init the zoomer, used by the constructors.
virtual bool accept(QPolygon &) const override
Check and correct a selected rectangle.
int i
virtual void begin() override
void setAxisScale(int axisId, double min, double max, double step=0)
Disable autoscaling and specify a fixed scale for a selected axis.
virtual void begin()
void zoomed(const QRectF &rect)
virtual void moveTo(const QPointF &)
Display only when the selection is active.
Definition: qwt_picker.h:162


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17