Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qevent.h>
00013 #include "qwt_plot.h"
00014 #include "qwt_plot_canvas.h"
00015 #include "qwt_scale_div.h"
00016 #include "qwt_double_interval.h"
00017 #include "qwt_plot_rescaler.h"
00018
00019 class QwtPlotRescaler::AxisData
00020 {
00021 public:
00022 AxisData():
00023 aspectRatio(1.0),
00024 expandingDirection(QwtPlotRescaler::ExpandUp)
00025 {
00026 }
00027
00028 double aspectRatio;
00029 QwtDoubleInterval intervalHint;
00030 QwtPlotRescaler::ExpandingDirection expandingDirection;
00031 mutable QwtScaleDiv scaleDiv;
00032 };
00033
00034 class QwtPlotRescaler::PrivateData
00035 {
00036 public:
00037 PrivateData():
00038 referenceAxis(QwtPlot::xBottom),
00039 rescalePolicy(QwtPlotRescaler::Expanding),
00040 isEnabled(false),
00041 inReplot(0)
00042 {
00043 }
00044
00045 int referenceAxis;
00046 RescalePolicy rescalePolicy;
00047 QwtPlotRescaler::AxisData axisData[QwtPlot::axisCnt];
00048 bool isEnabled;
00049
00050 mutable int inReplot;
00051 };
00052
00062 QwtPlotRescaler::QwtPlotRescaler(QwtPlotCanvas *canvas,
00063 int referenceAxis, RescalePolicy policy):
00064 QObject(canvas)
00065 {
00066 d_data = new PrivateData;
00067 d_data->referenceAxis = referenceAxis;
00068 d_data->rescalePolicy = policy;
00069
00070 setEnabled(true);
00071 }
00072
00074 QwtPlotRescaler::~QwtPlotRescaler()
00075 {
00076 delete d_data;
00077 }
00078
00088 void QwtPlotRescaler::setEnabled(bool on)
00089 {
00090 if ( d_data->isEnabled != on )
00091 {
00092 d_data->isEnabled = on;
00093
00094 QWidget *w = canvas();
00095 if ( w )
00096 {
00097 if ( d_data->isEnabled )
00098 w->installEventFilter(this);
00099 else
00100 w->removeEventFilter(this);
00101 }
00102 }
00103 }
00104
00109 bool QwtPlotRescaler::isEnabled() const
00110 {
00111 return d_data->isEnabled;
00112 }
00113
00120 void QwtPlotRescaler::setRescalePolicy(RescalePolicy policy)
00121 {
00122 d_data->rescalePolicy = policy;
00123 }
00124
00129 QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const
00130 {
00131 return d_data->rescalePolicy;
00132 }
00133
00140 void QwtPlotRescaler::setReferenceAxis(int axis)
00141 {
00142 d_data->referenceAxis = axis;
00143 }
00144
00149 int QwtPlotRescaler::referenceAxis() const
00150 {
00151 return d_data->referenceAxis;
00152 }
00153
00160 void QwtPlotRescaler::setExpandingDirection(
00161 ExpandingDirection direction)
00162 {
00163 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00164 setExpandingDirection(axis, direction);
00165 }
00166
00174 void QwtPlotRescaler::setExpandingDirection(
00175 int axis, ExpandingDirection direction)
00176 {
00177 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00178 d_data->axisData[axis].expandingDirection = direction;
00179 }
00180
00187 QwtPlotRescaler::ExpandingDirection
00188 QwtPlotRescaler::expandingDirection(int axis) const
00189 {
00190 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00191 return d_data->axisData[axis].expandingDirection;
00192
00193 return ExpandBoth;
00194 }
00195
00203 void QwtPlotRescaler::setAspectRatio(double ratio)
00204 {
00205 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00206 setAspectRatio(axis, ratio);
00207 }
00208
00217 void QwtPlotRescaler::setAspectRatio(int axis, double ratio)
00218 {
00219 if ( ratio < 0.0 )
00220 ratio = 0.0;
00221
00222 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00223 d_data->axisData[axis].aspectRatio = ratio;
00224 }
00225
00232 double QwtPlotRescaler::aspectRatio(int axis) const
00233 {
00234 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00235 return d_data->axisData[axis].aspectRatio;
00236
00237 return 0.0;
00238 }
00239
00240 void QwtPlotRescaler::setIntervalHint(int axis,
00241 const QwtDoubleInterval &interval)
00242 {
00243 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00244 d_data->axisData[axis].intervalHint = interval;
00245 }
00246
00247 QwtDoubleInterval QwtPlotRescaler::intervalHint(int axis) const
00248 {
00249 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00250 return d_data->axisData[axis].intervalHint;
00251
00252 return QwtDoubleInterval();
00253 }
00254
00256 QwtPlotCanvas *QwtPlotRescaler::canvas()
00257 {
00258 QObject *o = parent();
00259 if ( o && o->inherits("QwtPlotCanvas") )
00260 return (QwtPlotCanvas *)o;
00261
00262 return NULL;
00263 }
00264
00266 const QwtPlotCanvas *QwtPlotRescaler::canvas() const
00267 {
00268 return ((QwtPlotRescaler *)this)->canvas();
00269 }
00270
00272 QwtPlot *QwtPlotRescaler::plot()
00273 {
00274 QObject *w = canvas();
00275 if ( w )
00276 {
00277 w = w->parent();
00278 if ( w && w->inherits("QwtPlot") )
00279 return (QwtPlot *)w;
00280 }
00281
00282 return NULL;
00283 }
00284
00286 const QwtPlot *QwtPlotRescaler::plot() const
00287 {
00288 return ((QwtPlotRescaler *)this)->plot();
00289 }
00290
00292 bool QwtPlotRescaler::eventFilter(QObject *o, QEvent *e)
00293 {
00294 if ( o && o == canvas() )
00295 {
00296 switch(e->type())
00297 {
00298 case QEvent::Resize:
00299 canvasResizeEvent((QResizeEvent *)e);
00300 break;
00301 #if QT_VERSION >= 0x040000
00302 case QEvent::PolishRequest:
00303 rescale();
00304 break;
00305 #endif
00306 default:;
00307 }
00308 }
00309
00310 return false;
00311 }
00312
00313 void QwtPlotRescaler::canvasResizeEvent(QResizeEvent* e)
00314 {
00315 const int fw = 2 * canvas()->frameWidth();
00316 const QSize newSize = e->size() - QSize(fw, fw);
00317 const QSize oldSize = e->oldSize() - QSize(fw, fw);
00318
00319 rescale(oldSize, newSize);
00320 }
00321
00323 void QwtPlotRescaler::rescale() const
00324 {
00325 #if 0
00326 const int axis = referenceAxis();
00327 if ( axis < 0 || axis >= QwtPlot::axisCnt )
00328 return;
00329
00330 const QwtDoubleInterval hint = intervalHint(axis);
00331 if ( !hint.isNull() )
00332 {
00333 QwtPlot *plt = (QwtPlot *)plot();
00334
00335 const bool doReplot = plt->autoReplot();
00336 plt->setAutoReplot(false);
00337 plt->setAxisScale(axis, hint.minValue(), hint.maxValue());
00338 plt->setAutoReplot(doReplot);
00339 plt->updateAxes();
00340 }
00341 #endif
00342
00343 const QSize size = canvas()->contentsRect().size();
00344 rescale(size, size);
00345 }
00346
00353 void QwtPlotRescaler::rescale(
00354 const QSize &oldSize, const QSize &newSize) const
00355 {
00356 if ( newSize.isEmpty() )
00357 return;
00358
00359 QwtDoubleInterval intervals[QwtPlot::axisCnt];
00360 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00361 intervals[axis] = interval(axis);
00362
00363 const int refAxis = referenceAxis();
00364 intervals[refAxis] = expandScale(refAxis, oldSize, newSize);
00365
00366 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00367 {
00368 if ( aspectRatio(axis) > 0.0 && axis != refAxis )
00369 intervals[axis] = syncScale(axis, intervals[refAxis], newSize);
00370 }
00371
00372 updateScales(intervals);
00373 }
00374
00384 QwtDoubleInterval QwtPlotRescaler::expandScale( int axis,
00385 const QSize &oldSize, const QSize &newSize) const
00386 {
00387 const QwtDoubleInterval oldInterval = interval(axis);
00388
00389 QwtDoubleInterval expanded = oldInterval;
00390 switch(rescalePolicy())
00391 {
00392 case Fixed:
00393 {
00394 break;
00395 }
00396 case Expanding:
00397 {
00398 if ( !oldSize.isEmpty() )
00399 {
00400 double width = oldInterval.width();
00401 if ( orientation(axis) == Qt::Horizontal )
00402 width *= double(newSize.width()) / oldSize.width();
00403 else
00404 width *= double(newSize.height()) / oldSize.height();
00405
00406 expanded = expandInterval(oldInterval,
00407 width, expandingDirection(axis));
00408 }
00409 break;
00410 }
00411 case Fitting:
00412 {
00413 double dist = 0.0;
00414 for ( int ax = 0; ax < QwtPlot::axisCnt; ax++ )
00415 {
00416 const double d = pixelDist(ax, newSize);
00417 if ( d > dist )
00418 dist = d;
00419 }
00420 if ( dist > 0.0 )
00421 {
00422 double width;
00423 if ( orientation(axis) == Qt::Horizontal )
00424 width = newSize.width() * dist;
00425 else
00426 width = newSize.height() * dist;
00427
00428 expanded = expandInterval(intervalHint(axis),
00429 width, expandingDirection(axis));
00430 }
00431 break;
00432 }
00433 }
00434
00435 return expanded;
00436 }
00437
00445 QwtDoubleInterval QwtPlotRescaler::syncScale(int axis,
00446 const QwtDoubleInterval& reference, const QSize &size) const
00447 {
00448 double dist;
00449 if ( orientation(referenceAxis()) == Qt::Horizontal )
00450 dist = reference.width() / size.width();
00451 else
00452 dist = reference.width() / size.height();
00453
00454 if ( orientation(axis) == Qt::Horizontal )
00455 dist *= size.width();
00456 else
00457 dist *= size.height();
00458
00459 dist /= aspectRatio(axis);
00460
00461 QwtDoubleInterval intv;
00462 if ( rescalePolicy() == Fitting )
00463 intv = intervalHint(axis);
00464 else
00465 intv = interval(axis);
00466
00467 intv = expandInterval(intv, dist, expandingDirection(axis));
00468
00469 return intv;
00470 }
00471
00476 Qt::Orientation QwtPlotRescaler::orientation(int axis) const
00477 {
00478 if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight )
00479 return Qt::Vertical;
00480
00481 return Qt::Horizontal;
00482 }
00483
00488 QwtDoubleInterval QwtPlotRescaler::interval(int axis) const
00489 {
00490 if ( axis < 0 || axis >= QwtPlot::axisCnt )
00491 return QwtDoubleInterval();
00492
00493 const QwtPlot *plt = plot();
00494
00495 const double v1 = plt->axisScaleDiv(axis)->lowerBound();
00496 const double v2 = plt->axisScaleDiv(axis)->upperBound();
00497
00498 return QwtDoubleInterval(v1, v2).normalized();
00499 }
00500
00510 QwtDoubleInterval QwtPlotRescaler::expandInterval(
00511 const QwtDoubleInterval &interval, double width,
00512 ExpandingDirection direction) const
00513 {
00514 QwtDoubleInterval expanded = interval;
00515
00516 switch(direction)
00517 {
00518 case ExpandUp:
00519 expanded.setMinValue(interval.minValue());
00520 expanded.setMaxValue(interval.minValue() + width);
00521 break;
00522 case ExpandDown:
00523 expanded.setMaxValue(interval.maxValue());
00524 expanded.setMinValue(interval.maxValue() - width);
00525 break;
00526 case ExpandBoth:
00527 default:
00528 expanded.setMinValue(interval.minValue() +
00529 interval.width() / 2.0 - width / 2.0);
00530 expanded.setMaxValue(expanded.minValue() + width);
00531 }
00532 return expanded;
00533 }
00534
00535 double QwtPlotRescaler::pixelDist(int axis, const QSize &size) const
00536 {
00537 const QwtDoubleInterval intv = intervalHint(axis);
00538
00539 double dist = 0.0;
00540 if ( !intv.isNull() )
00541 {
00542 if ( axis == referenceAxis() )
00543 dist = intv.width();
00544 else
00545 {
00546 const double r = aspectRatio(axis);
00547 if ( r > 0.0 )
00548 dist = intv.width() * r;
00549 }
00550 }
00551
00552 if ( dist > 0.0 )
00553 {
00554 if ( orientation(axis) == Qt::Horizontal )
00555 dist /= size.width();
00556 else
00557 dist /= size.height();
00558 }
00559
00560 return dist;
00561 }
00562
00568 void QwtPlotRescaler::updateScales(
00569 QwtDoubleInterval intervals[QwtPlot::axisCnt]) const
00570 {
00571 if ( d_data->inReplot >= 5 )
00572 {
00573 return;
00574 }
00575
00576 QwtPlot *plt = (QwtPlot *)plot();
00577
00578 const bool doReplot = plt->autoReplot();
00579 plt->setAutoReplot(false);
00580
00581 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00582 {
00583 if ( axis == referenceAxis() || aspectRatio(axis) > 0.0 )
00584 {
00585 double v1 = intervals[axis].minValue();
00586 double v2 = intervals[axis].maxValue();
00587
00588 if ( plt->axisScaleDiv(axis)->lowerBound() >
00589 plt->axisScaleDiv(axis)->upperBound() )
00590 {
00591 qSwap(v1, v2);
00592 }
00593
00594 if ( d_data->inReplot >= 1 )
00595 {
00596 d_data->axisData[axis].scaleDiv = *plt->axisScaleDiv(axis);
00597 }
00598
00599 if ( d_data->inReplot >= 2 )
00600 {
00601 QwtValueList ticks[QwtScaleDiv::NTickTypes];
00602 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
00603 ticks[i] = d_data->axisData[axis].scaleDiv.ticks(i);
00604
00605 plt->setAxisScaleDiv(axis, QwtScaleDiv(v1, v2, ticks));
00606 }
00607 else
00608 {
00609 plt->setAxisScale(axis, v1, v2);
00610 }
00611 }
00612 }
00613
00614 plt->setAutoReplot(doReplot);
00615
00616 d_data->inReplot++;
00617 plt->replot();
00618 d_data->inReplot--;
00619 }