Qwt User's Guide 6.3.0

Loading...
Searching...
No Matches
qwt_plot_rescaler.cpp
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
18 class QwtPlotRescaler::AxisData
19{
20 public:
21 AxisData()
22 : aspectRatio( 1.0 )
23 , expandingDirection( QwtPlotRescaler::ExpandUp )
24 {
25 }
26
27 double aspectRatio;
28 QwtInterval intervalHint;
29 QwtPlotRescaler::ExpandingDirection expandingDirection;
30 mutable QwtScaleDiv scaleDiv;
31};
32
33 class QwtPlotRescaler::PrivateData
34{
35 public:
36 PrivateData()
37 : referenceAxis( QwtAxis::XBottom )
38 , rescalePolicy( QwtPlotRescaler::Expanding )
39 , isEnabled( false )
40 , inReplot( 0 )
41 {
42 }
43
44 QwtPlotRescaler::AxisData* axisData( QwtAxisId axisId )
45 {
46 if ( !QwtAxis::isValid( axisId ) )
47 return NULL;
48
49 return &m_axisData[ axisId];
50 }
51
52 QwtAxisId referenceAxis;
53 RescalePolicy rescalePolicy;
54 bool isEnabled;
55
56 mutable int inReplot;
57
58 private:
59 QwtPlotRescaler::AxisData m_axisData[QwtAxis::AxisPositions];
60};
61
71 QwtPlotRescaler::QwtPlotRescaler( QWidget* canvas,
72 QwtAxisId referenceAxis, RescalePolicy policy )
73 : QObject( canvas )
74{
75 m_data = new PrivateData;
76 m_data->referenceAxis = referenceAxis;
77 m_data->rescalePolicy = policy;
78
79 setEnabled( true );
80}
81
83 QwtPlotRescaler::~QwtPlotRescaler()
84{
85 delete m_data;
86}
87
97 void QwtPlotRescaler::setEnabled( bool on )
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
118 bool QwtPlotRescaler::isEnabled() const
119{
120 return m_data->isEnabled;
121}
122
129 void QwtPlotRescaler::setRescalePolicy( RescalePolicy policy )
130{
131 m_data->rescalePolicy = policy;
132}
133
138 QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const
139{
140 return m_data->rescalePolicy;
141}
142
149 void QwtPlotRescaler::setReferenceAxis( QwtAxisId axisId )
150{
151 m_data->referenceAxis = axisId;
152}
153
158QwtAxisId QwtPlotRescaler::referenceAxis() const
159{
160 return m_data->referenceAxis;
161}
162
169 void QwtPlotRescaler::setExpandingDirection(
170 ExpandingDirection direction )
171{
172 for ( int axis = 0; axis < QwtAxis::AxisPositions; axis++ )
173 setExpandingDirection( axis, direction );
174}
175
183 void QwtPlotRescaler::setExpandingDirection(
184 QwtAxisId axisId, ExpandingDirection direction )
185{
186 if ( AxisData* axisData = m_data->axisData( axisId ) )
187 axisData->expandingDirection = direction;
188}
189
196 QwtPlotRescaler::ExpandingDirection
197 QwtPlotRescaler::expandingDirection( QwtAxisId axisId ) const
198{
199 if ( const AxisData* axisData = m_data->axisData( axisId ) )
200 return axisData->expandingDirection;
201
202 return ExpandBoth;
203}
204
212 void QwtPlotRescaler::setAspectRatio( double ratio )
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
243 double QwtPlotRescaler::aspectRatio( QwtAxisId axisId ) const
244{
245 if ( AxisData* axisData = m_data->axisData( axisId ) )
246 return axisData->aspectRatio;
247
248 return 0.0;
249}
250
261 void QwtPlotRescaler::setIntervalHint( QwtAxisId axisId,
262 const QwtInterval& interval )
263{
264 if ( AxisData* axisData = m_data->axisData( axisId ) )
265 axisData->intervalHint = interval;
266}
267
273 QwtInterval QwtPlotRescaler::intervalHint( QwtAxisId axisId ) const
274{
275 if ( AxisData* axisData = m_data->axisData( axisId ) )
276 return axisData->intervalHint;
277
278 return QwtInterval();
279}
280
282QWidget* QwtPlotRescaler::canvas()
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
294 QwtPlot* QwtPlotRescaler::plot()
295{
296 QWidget* w = canvas();
297 if ( w )
298 w = w->parentWidget();
299
300 return qobject_cast< QwtPlot* >( w );
301}
302
304 const QwtPlot* QwtPlotRescaler::plot() const
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
355 void QwtPlotRescaler::rescale() const
356{
357 const QSize size = canvas()->contentsRect().size();
358 rescale( size, size );
359}
360
367 void QwtPlotRescaler::rescale(
368 const QSize& oldSize, const QSize& newSize ) const
369{
370 if ( newSize.isEmpty() )
371 return;
372
373 QwtInterval intervals[QwtAxis::AxisPositions];
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
405 QwtInterval QwtPlotRescaler::expandScale( QwtAxisId axisId,
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
469 QwtInterval QwtPlotRescaler::syncScale( QwtAxisId axisId,
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
500Qt::Orientation QwtPlotRescaler::orientation( QwtAxisId axisId ) const
501{
502 return QwtAxis::isYAxis( axisId ) ? Qt::Vertical : Qt::Horizontal;
503}
504
509 QwtInterval QwtPlotRescaler::interval( QwtAxisId axisId ) const
510{
511 if ( !plot()->isAxisValid( axisId ) )
512 return QwtInterval();
513
514 return plot()->axisScaleDiv( axisId ).interval().normalized();
515}
516
526 QwtInterval QwtPlotRescaler::expandInterval(
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
588 void QwtPlotRescaler::updateScales(
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 {
619 QList< double > ticks[QwtScaleDiv::NTickTypes];
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 );
639 canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false );
640 }
641
642 plt->setAutoReplot( doReplot );
643
644 m_data->inReplot++;
645 plt->replot();
646 m_data->inReplot--;
647
648 if ( canvas && immediatePaint )
649 {
650 canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true );
651 }
652}
653
654#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