qwt_plot_rescaler.cpp
Go to the documentation of this file.
1 /******************************************************************************
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_rescaler.h"
11 #include "qwt_plot.h"
12 #include "qwt_scale_div.h"
13 #include "qwt_interval.h"
14 #include "qwt_plot_canvas.h"
15 
16 #include <qevent.h>
17 
19 {
20  public:
22  : aspectRatio( 1.0 )
24  {
25  }
26 
27  double aspectRatio;
31 };
32 
34 {
35  public:
39  , isEnabled( false )
40  , inReplot( 0 )
41  {
42  }
43 
45  {
46  if ( !QwtAxis::isValid( axisId ) )
47  return NULL;
48 
49  return &m_axisData[ axisId];
50  }
51 
54  bool isEnabled;
55 
56  mutable int inReplot;
57 
58  private:
60 };
61 
73  : QObject( canvas )
74 {
75  m_data = new PrivateData;
77  m_data->rescalePolicy = policy;
78 
79  setEnabled( true );
80 }
81 
84 {
85  delete m_data;
86 }
87 
98 {
99  if ( m_data->isEnabled != on )
100  {
101  m_data->isEnabled = on;
102 
103  QWidget* w = canvas();
104  if ( w )
105  {
106  if ( m_data->isEnabled )
107  w->installEventFilter( this );
108  else
109  w->removeEventFilter( this );
110  }
111  }
112 }
113 
119 {
120  return m_data->isEnabled;
121 }
122 
130 {
131  m_data->rescalePolicy = policy;
132 }
133 
139 {
140  return m_data->rescalePolicy;
141 }
142 
150 {
151  m_data->referenceAxis = axisId;
152 }
153 
159 {
160  return m_data->referenceAxis;
161 }
162 
170  ExpandingDirection direction )
171 {
172  for ( int axis = 0; axis < QwtAxis::AxisPositions; axis++ )
173  setExpandingDirection( axis, direction );
174 }
175 
184  QwtAxisId axisId, ExpandingDirection direction )
185 {
186  if ( AxisData* axisData = m_data->axisData( axisId ) )
187  axisData->expandingDirection = direction;
188 }
189 
198 {
199  if ( const AxisData* axisData = m_data->axisData( axisId ) )
200  return axisData->expandingDirection;
201 
202  return ExpandBoth;
203 }
204 
213 {
214  for ( int axis = 0; axis < QwtAxis::AxisPositions; axis++ )
215  setAspectRatio( axis, ratio );
216 }
217 
226 void QwtPlotRescaler::setAspectRatio( QwtAxisId axisId, double ratio )
227 {
228  if ( AxisData* axisData = m_data->axisData( axisId ) )
229  {
230  if ( ratio < 0.0 )
231  ratio = 0.0;
232 
233  axisData->aspectRatio = ratio;
234  }
235 }
236 
244 {
245  if ( AxisData* axisData = m_data->axisData( axisId ) )
246  return axisData->aspectRatio;
247 
248  return 0.0;
249 }
250 
262  const QwtInterval& interval )
263 {
264  if ( AxisData* axisData = m_data->axisData( axisId ) )
265  axisData->intervalHint = interval;
266 }
267 
274 {
275  if ( AxisData* axisData = m_data->axisData( axisId ) )
276  return axisData->intervalHint;
277 
278  return QwtInterval();
279 }
280 
283 {
284  return qobject_cast< QWidget* >( parent() );
285 }
286 
288 const QWidget* QwtPlotRescaler::canvas() const
289 {
290  return qobject_cast< const QWidget* >( parent() );
291 }
292 
295 {
296  QWidget* w = canvas();
297  if ( w )
298  w = w->parentWidget();
299 
300  return qobject_cast< QwtPlot* >( w );
301 }
302 
305 {
306  const QWidget* w = canvas();
307  if ( w )
308  w = w->parentWidget();
309 
310  return qobject_cast< const QwtPlot* >( w );
311 }
312 
314 bool QwtPlotRescaler::eventFilter( QObject* object, QEvent* event )
315 {
316  if ( object && object == canvas() )
317  {
318  switch ( event->type() )
319  {
320  case QEvent::Resize:
321  {
322  canvasResizeEvent( static_cast< QResizeEvent* >( event ) );
323  break;
324  }
325  case QEvent::PolishRequest:
326  {
327  rescale();
328  break;
329  }
330  default:;
331  }
332  }
333 
334  return false;
335 }
336 
343 void QwtPlotRescaler::canvasResizeEvent( QResizeEvent* event )
344 {
345  const QMargins m = canvas()->contentsMargins();
346  const QSize marginSize( m.left() + m.right(), m.top() + m.bottom() );
347 
348  const QSize newSize = event->size() - marginSize;
349  const QSize oldSize = event->oldSize() - marginSize;
350 
351  rescale( oldSize, newSize );
352 }
353 
356 {
357  const QSize size = canvas()->contentsRect().size();
358  rescale( size, size );
359 }
360 
368  const QSize& oldSize, const QSize& newSize ) const
369 {
370  if ( newSize.isEmpty() )
371  return;
372 
374  for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
375  {
376  const QwtAxisId axisId( axisPos );
377  intervals[axisPos] = interval( axisId );
378  }
379 
380  const QwtAxisId refAxis = referenceAxis();
381  intervals[refAxis] = expandScale( refAxis, oldSize, newSize );
382 
383  for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
384  {
385  const QwtAxisId axisId( axisPos );
386  if ( aspectRatio( axisId ) > 0.0 && axisId != refAxis )
387  {
388  intervals[axisPos] = syncScale(
389  axisId, intervals[refAxis], newSize );
390  }
391  }
392 
393  updateScales( intervals );
394 }
395 
406  const QSize& oldSize, const QSize& newSize ) const
407 {
408  const QwtInterval oldInterval = interval( axisId );
409 
410  QwtInterval expanded = oldInterval;
411  switch ( rescalePolicy() )
412  {
413  case Fixed:
414  {
415  break; // do nothing
416  }
417  case Expanding:
418  {
419  if ( !oldSize.isEmpty() )
420  {
421  double width = oldInterval.width();
422  if ( orientation( axisId ) == Qt::Horizontal )
423  width *= double( newSize.width() ) / oldSize.width();
424  else
425  width *= double( newSize.height() ) / oldSize.height();
426 
427  expanded = expandInterval( oldInterval,
428  width, expandingDirection( axisId ) );
429  }
430  break;
431  }
432  case Fitting:
433  {
434  double dist = 0.0;
435  for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
436  {
437  const QwtAxisId axisId( axisPos );
438  const double d = pixelDist( axisId, newSize );
439  if ( d > dist )
440  dist = d;
441  }
442  if ( dist > 0.0 )
443  {
444  double width;
445  if ( orientation( axisId ) == Qt::Horizontal )
446  width = newSize.width() * dist;
447  else
448  width = newSize.height() * dist;
449 
450  expanded = expandInterval( intervalHint( axisId ),
451  width, expandingDirection( axisId ) );
452  }
453  break;
454  }
455  }
456 
457  return expanded;
458 }
459 
470  const QwtInterval& reference, const QSize& size ) const
471 {
472  double dist;
473  if ( orientation( referenceAxis() ) == Qt::Horizontal )
474  dist = reference.width() / size.width();
475  else
476  dist = reference.width() / size.height();
477 
478  if ( orientation( axisId ) == Qt::Horizontal )
479  dist *= size.width();
480  else
481  dist *= size.height();
482 
483  dist /= aspectRatio( axisId );
484 
485  QwtInterval intv;
486  if ( rescalePolicy() == Fitting )
487  intv = intervalHint( axisId );
488  else
489  intv = interval( axisId );
490 
491  intv = expandInterval( intv, dist, expandingDirection( axisId ) );
492 
493  return intv;
494 }
495 
500 Qt::Orientation QwtPlotRescaler::orientation( QwtAxisId axisId ) const
501 {
502  return QwtAxis::isYAxis( axisId ) ? Qt::Vertical : Qt::Horizontal;
503 }
504 
510 {
511  if ( !plot()->isAxisValid( axisId ) )
512  return QwtInterval();
513 
514  return plot()->axisScaleDiv( axisId ).interval().normalized();
515 }
516 
527  const QwtInterval& interval, double width,
528  ExpandingDirection direction ) const
529 {
530  QwtInterval expanded = interval;
531 
532  switch ( direction )
533  {
534  case ExpandUp:
535  expanded.setMinValue( interval.minValue() );
536  expanded.setMaxValue( interval.minValue() + width );
537  break;
538 
539  case ExpandDown:
540  expanded.setMaxValue( interval.maxValue() );
541  expanded.setMinValue( interval.maxValue() - width );
542  break;
543 
544  case ExpandBoth:
545  default:
546  expanded.setMinValue( interval.minValue() +
547  interval.width() / 2.0 - width / 2.0 );
548  expanded.setMaxValue( expanded.minValue() + width );
549  }
550  return expanded;
551 }
552 
553 double QwtPlotRescaler::pixelDist( QwtAxisId axisId, const QSize& size ) const
554 {
555  const QwtInterval intv = intervalHint( axisId );
556 
557  double dist = 0.0;
558  if ( !intv.isNull() )
559  {
560  if ( axisId == referenceAxis() )
561  {
562  dist = intv.width();
563  }
564  else
565  {
566  const double r = aspectRatio( axisId );
567  if ( r > 0.0 )
568  dist = intv.width() * r;
569  }
570  }
571 
572  if ( dist > 0.0 )
573  {
574  if ( orientation( axisId ) == Qt::Horizontal )
575  dist /= size.width();
576  else
577  dist /= size.height();
578  }
579 
580  return dist;
581 }
582 
589  QwtInterval intervals[QwtAxis::AxisPositions] ) const
590 {
591  if ( m_data->inReplot >= 5 )
592  {
593  return;
594  }
595 
596  QwtPlot* plt = const_cast< QwtPlot* >( plot() );
597 
598  const bool doReplot = plt->autoReplot();
599  plt->setAutoReplot( false );
600 
601  for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
602  {
603  {
604  const QwtAxisId axisId( axisPos );
605 
606  if ( axisId == referenceAxis() || aspectRatio( axisId ) > 0.0 )
607  {
608  double v1 = intervals[axisPos].minValue();
609  double v2 = intervals[axisPos].maxValue();
610 
611  if ( !plt->axisScaleDiv( axisId ).isIncreasing() )
612  qSwap( v1, v2 );
613 
614  if ( m_data->inReplot >= 1 )
615  m_data->axisData( axisId )->scaleDiv = plt->axisScaleDiv( axisId );
616 
617  if ( m_data->inReplot >= 2 )
618  {
620  for ( int t = 0; t < QwtScaleDiv::NTickTypes; t++ )
621  ticks[t] = m_data->axisData( axisId )->scaleDiv.ticks( t );
622 
623  plt->setAxisScaleDiv( axisId, QwtScaleDiv( v1, v2, ticks ) );
624  }
625  else
626  {
627  plt->setAxisScale( axisId, v1, v2 );
628  }
629  }
630  }
631  }
632 
633  QwtPlotCanvas* canvas = qobject_cast< QwtPlotCanvas* >( plt->canvas() );
634 
635  bool immediatePaint = false;
636  if ( canvas )
637  {
638  immediatePaint = canvas->testPaintAttribute( QwtPlotCanvas::ImmediatePaint );
640  }
641 
642  plt->setAutoReplot( doReplot );
643 
644  m_data->inReplot++;
645  plt->replot();
646  m_data->inReplot--;
647 
648  if ( canvas && immediatePaint )
649  {
651  }
652 }
653 
654 #if QWT_MOC_INCLUDE
655 #include "moc_qwt_plot_rescaler.cpp"
656 #endif
double aspectRatio(QwtAxisId) const
d
QwtAxisId referenceAxis() const
Qt::Orientation orientation(QwtAxisId) const
void setRescalePolicy(RescalePolicy)
ExpandingDirection expandingDirection(QwtAxisId) const
QwtInterval expandInterval(const QwtInterval &, double width, ExpandingDirection) const
bool testPaintAttribute(PaintAttribute) const
void setAxisScaleDiv(QwtAxisId, const QwtScaleDiv &)
Disable autoscaling and specify a fixed scale for a selected axis.
QList< double > ticks(int tickType) const
bool isValid(int axisPos)
Definition: qwt_axis.h:45
bool isYAxis(int axisPos)
Definition: qwt_axis.h:57
A class representing an interval.
Definition: qwt_interval.h:22
virtual void canvasResizeEvent(QResizeEvent *)
double minValue() const
Definition: qwt_interval.h:192
bool isEnabled() const
void setAutoReplot(bool=true)
Set or reset the autoReplot option.
Definition: qwt_plot.cpp:310
QwtPlotRescaler::AxisData * axisData(QwtAxisId axisId)
virtual void replot()
Redraw the plot.
Definition: qwt_plot.cpp:545
const QwtScaleDiv & axisScaleDiv(QwtAxisId) const
Return the scale division of a specified axis.
A class representing a scale division.
Definition: qwt_scale_div.h:33
void rescale() const
Adjust the plot axes scales.
Canvas of a QwtPlot.
bool isNull() const
Definition: qwt_interval.h:314
A 2-D plotting widget.
Definition: qwt_plot.h:78
void setReferenceAxis(QwtAxisId)
virtual QwtInterval syncScale(QwtAxisId, const QwtInterval &reference, const QSize &size) const
double pixelDist(QwtAxisId, const QSize &) const
virtual void updateScales(QwtInterval intervals[QwtAxis::AxisPositions]) const
QwtInterval interval() const
bool isIncreasing() const
Check if the scale division is increasing( lowerBound() <= upperBound() )
The lower limit of the scale is adjusted.
virtual QwtInterval expandScale(QwtAxisId, const QSize &oldSize, const QSize &newSize) const
bool autoReplot
Definition: qwt_plot.h:85
QwtInterval intervalHint(QwtAxisId) const
void setExpandingDirection(ExpandingDirection)
QwtInterval interval(QwtAxisId) const
void setEnabled(bool)
En/disable the rescaler.
Both limits of the scale are adjusted.
virtual ~QwtPlotRescaler()
Destructor.
basic_reference< false > reference
Definition: forward.hpp:1100
QwtPlotRescaler takes care of fixed aspect ratios for plot scales.
void setPaintAttribute(PaintAttribute, bool on=true)
Changing the paint attributes.
double width() const
Return the width of an interval.
Definition: qwt_interval.h:227
Number of valid tick types.
Definition: qwt_scale_div.h:52
int QwtAxisId
Axis identifier.
Definition: qwt_axis_id.h:26
QwtPlotRescaler::ExpandingDirection expandingDirection
void setMinValue(double)
Definition: qwt_interval.h:176
QWidget * canvas()
Definition: qwt_plot.cpp:463
The upper limit of the scale is adjusted.
void setAspectRatio(double ratio)
void setAxisScale(QwtAxisId, double min, double max, double stepSize=0)
Disable autoscaling and specify a fixed scale for a selected axis.
span_constexpr std::size_t size(span< T, Extent > const &spn)
Definition: span.hpp:1485
QwtPlotRescaler(QWidget *canvas, QwtAxisId referenceAxis=QwtAxis::XBottom, RescalePolicy=Expanding)
void setMaxValue(double)
Definition: qwt_interval.h:186
X axis below the canvas.
Definition: qwt_axis.h:30
QwtInterval normalized() const
Normalize the limits of the interval.
virtual bool eventFilter(QObject *, QEvent *) QWT_OVERRIDE
Event filter for the plot canvas.
double maxValue() const
Definition: qwt_interval.h:198
void setIntervalHint(QwtAxisId, const QwtInterval &)
RescalePolicy rescalePolicy() const
PrivateData * m_data


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:38