From cfe9b5626d40dfc70434a3a34ce1ceaf88448ae6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Nov 2016 09:09:50 +0100 Subject: [PATCH] #870 Show closest curve point y-value and a plot marker --- .../UserInterface/RiuSummaryQwtPlot.cpp | 178 ++++++++++++++---- .../UserInterface/RiuSummaryQwtPlot.h | 9 + 2 files changed, 148 insertions(+), 39 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp index ee0ee14b78..f1695f7df3 100644 --- a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp @@ -32,15 +32,60 @@ #include "qwt_plot_curve.h" #include "qwt_plot_grid.h" #include "qwt_plot_layout.h" +#include "qwt_plot_marker.h" #include "qwt_plot_panner.h" +#include "qwt_plot_picker.h" #include "qwt_plot_zoomer.h" #include "qwt_scale_engine.h" +#include "qwt_symbol.h" #include #include #include + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RiuQwtPlotPicker : public QwtPlotPicker +{ +public: + RiuQwtPlotPicker(QWidget *canvas) + : QwtPlotPicker(canvas) + { + } + +protected: + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + virtual QwtText trackerText(const QPoint& pos) const override + { + QwtText txt; + + const RiuSummaryQwtPlot* sumPlot = dynamic_cast(this->plot()); + if (sumPlot) + { + int closestYAxis = QwtPlot::yLeft; + QPointF closestPoint = sumPlot->closestCurvePoint(pos, &closestYAxis); + if (!closestPoint.isNull()) + { + QString str = QString::number(closestPoint.y()); + + txt.setText(str); + } + + RiuSummaryQwtPlot* nonConstPlot = const_cast(sumPlot); + nonConstPlot->updateClosestCurvePointMarker(closestPoint, closestYAxis); + } + + return txt; + } +}; + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -75,6 +120,15 @@ RiuSummaryQwtPlot::RiuSummaryQwtPlot(RimSummaryPlot* plotDefinition, QWidget* pa RiuQwtScalePicker* scalePicker = new RiuQwtScalePicker(this); connect(scalePicker, SIGNAL(clicked(int, double)), this, SLOT(onAxisClicked(int, double))); + + // Create a plot picker to display values next to mouse cursor + m_plotPicker = new RiuQwtPlotPicker(this->canvas()); + m_plotPicker->setTrackerMode(QwtPicker::AlwaysOn); + + m_plotMarker = new QwtPlotMarker; + + // QwtPlotMarker takes ownership of the symbol, it is deleted in destructor of QwtPlotMarker + m_plotMarker->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, Qt::NoBrush, QPen(Qt::black), QSize(9, 9))); } //-------------------------------------------------------------------------------------------------- @@ -89,6 +143,9 @@ RiuSummaryQwtPlot::~RiuSummaryQwtPlot() { m_plotDefinition->handleViewerDeletion(); } + + m_plotMarker->detach(); + delete m_plotMarker; } //-------------------------------------------------------------------------------------------------- @@ -135,6 +192,84 @@ void RiuSummaryQwtPlot::setZoomWindow(const QwtInterval& leftAxis, const QwtInte } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QPointF RiuSummaryQwtPlot::closestCurvePoint(const QPoint& pos, int* yAxis) const +{ + QPointF p; + + QwtPlotCurve* closestCurve = nullptr; + double distMin = DBL_MAX; + int closestPointIndex = -1; + + const QwtPlotItemList& itmList = itemList(); + for (QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); it++) + { + if ((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) + { + QwtPlotCurve* candidateCurve = static_cast(*it); + double dist = DBL_MAX; + int pointIndexCandidate = candidateCurve->closestPoint(pos, &dist); + if (dist < distMin) + { + closestCurve = candidateCurve; + distMin = dist; + closestPointIndex = pointIndexCandidate; + } + } + } + + if (closestCurve && distMin < 50) + { + p = closestCurve->sample(closestPointIndex); + + if (yAxis) *yAxis = closestCurve->yAxis(); + } + + return p; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryQwtPlot::updateClosestCurvePointMarker(const QPointF& closestPoint, int yAxis) +{ + bool replotRequired = false; + + if (!closestPoint.isNull()) + { + if (!m_plotMarker->plot()) + { + m_plotMarker->attach(this); + + replotRequired = true; + } + + if (m_plotMarker->value() != closestPoint) + { + m_plotMarker->setValue(closestPoint.x(), closestPoint.y()); + + // Set y-axis to be able to support more than one y-axis. Default y-axis is left axis. + // TODO : Should use a color or other visual indicator to show what axis the curve relates to + m_plotMarker->setYAxis(yAxis); + + replotRequired = true; + } + } + else + { + if (m_plotMarker->plot()) + { + m_plotMarker->detach(); + + replotRequired = true; + } + } + + if (replotRequired) this->replot(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -207,47 +342,12 @@ bool RiuSummaryQwtPlot::eventFilter(QObject* watched, QEvent* event) { if(watched == canvas()) { - QWheelEvent* wheelEvent = dynamic_cast(event); - if(wheelEvent) + QMouseEvent* mouseEvent = dynamic_cast(event); + if(mouseEvent) { - #if 0 - if(!m_plotDefinition) + if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QMouseEvent::MouseButtonRelease) { - return QwtPlot::eventFilter(watched, event); - } - - if(wheelEvent->modifiers() & Qt::ControlModifier) - { - QwtScaleMap scaleMap = canvasMap(QwtPlot::yLeft); - double zoomCenter = scaleMap.invTransform(wheelEvent->pos().y()); - - if(wheelEvent->delta() > 0) - { - plotDefinition->setDepthZoomByFactorAndCenter(RIU_SCROLLWHEEL_ZOOMFACTOR, zoomCenter); - } - else - { - plotDefinition->setDepthZoomByFactorAndCenter(1.0/RIU_SCROLLWHEEL_ZOOMFACTOR, zoomCenter); - } - } - else - { - plotDefinition->panDepth(wheelEvent->delta() < 0 ? RIU_SCROLLWHEEL_PANFACTOR : -RIU_SCROLLWHEEL_PANFACTOR); - } - - event->accept(); - return true; - #endif - } - else - { - QMouseEvent* mouseEvent = dynamic_cast(event); - if(mouseEvent) - { - if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QMouseEvent::MouseButtonRelease) - { - selectClosestCurve(mouseEvent->pos()); - } + selectClosestCurve(mouseEvent->pos()); } } } diff --git a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h index 0f2c0425a6..f6360eda64 100644 --- a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h @@ -27,6 +27,8 @@ class QwtPlotCurve; class QwtPlotGrid; class QwtPlotZoomer; class QwtInterval; +class QwtPicker; +class QwtPlotMarker; class RimSummaryPlot; @@ -52,12 +54,16 @@ public: const QwtInterval& rightAxis, const QwtInterval& timeAxis); + QPointF closestCurvePoint(const QPoint& pos, int* yAxis) const; + void updateClosestCurvePointMarker(const QPointF& pos, int yAxis); + protected: virtual bool eventFilter(QObject* watched, QEvent* event); private: void setDefaults(); void selectClosestCurve(const QPoint& pos); + void showToolTip(const QPoint& pos); private slots: void onZoomedSlot( ); @@ -65,6 +71,9 @@ private slots: private: QwtPlotGrid* m_grid; + QwtPicker* m_plotPicker; + QwtPlotMarker* m_plotMarker; + caf::PdmPointer m_plotDefinition; QPointer m_zoomerLeft;