From 7a954804ef48f1d4f5b5f6ca16d249f0a02caa20 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Wed, 2 Mar 2022 13:46:06 +0100 Subject: [PATCH] #8451 Qt Charts: show fewer curve symbols. The "Symbol Skip Distance" is used to space the symbols. Fixes #8451. --- .../ProjectDataModel/RimPlotCurve.cpp | 2 +- .../Summary/RimSummaryPlot.cpp | 1 + .../UserInterface/CMakeLists_files.cmake | 1 + .../UserInterface/RiuPlotWidget.cpp | 7 ++ .../UserInterface/RiuPlotWidget.h | 2 + .../UserInterface/RiuQtChartsPlotCurve.cpp | 109 ++++++++++++++++-- .../UserInterface/RiuQtChartsPlotCurve.h | 8 +- .../UserInterface/RiuQtChartsPlotWidget.cpp | 64 +++++++--- .../UserInterface/RiuQtChartsPlotWidget.h | 13 ++- 9 files changed, 175 insertions(+), 32 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/RimPlotCurve.cpp b/ApplicationLibCode/ProjectDataModel/RimPlotCurve.cpp index 4691ffa21a..cb51c7657e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimPlotCurve.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimPlotCurve.cpp @@ -892,8 +892,8 @@ void RimPlotCurve::updateCurveAppearance() curveColor, fillBrush ); - m_plotCurve->setSymbol( symbol ); m_plotCurve->setSymbolSkipPixelDistance( m_curveAppearance->symbolSkipDistance() ); + m_plotCurve->setSymbol( symbol ); // Make sure the legend lines are long enough to distinguish between line types. // Standard width in Qwt is 8 which is too short. diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp index e36c51c99f..d6a9a20ff8 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp @@ -1590,6 +1590,7 @@ void RimSummaryPlot::updateZoomInParentPlot() plotWidget()->updateAxes(); updateZoomFromParentPlot(); + plotWidget()->updateZoomDependentCurveProperties(); plotWidget()->scheduleReplot(); } } diff --git a/ApplicationLibCode/UserInterface/CMakeLists_files.cmake b/ApplicationLibCode/UserInterface/CMakeLists_files.cmake index 375dcf73b4..b3dbc98381 100644 --- a/ApplicationLibCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/UserInterface/CMakeLists_files.cmake @@ -226,6 +226,7 @@ if(RESINSIGHT_USE_QT_CHARTS) list(APPEND QT_MOC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/RiuQtChartsPlotWidget.h ${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQtChartsPlot.h + ${CMAKE_CURRENT_LIST_DIR}/RiuQtChartsPlotCurve.h ) endif() diff --git a/ApplicationLibCode/UserInterface/RiuPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuPlotWidget.cpp index 795a2e659f..fff9a32722 100644 --- a/ApplicationLibCode/UserInterface/RiuPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuPlotWidget.cpp @@ -323,3 +323,10 @@ int RiuPlotWidget::defaultMinimumWidth() { return 80; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuPlotWidget::updateZoomDependentCurveProperties() +{ +} diff --git a/ApplicationLibCode/UserInterface/RiuPlotWidget.h b/ApplicationLibCode/UserInterface/RiuPlotWidget.h index 42ab278c76..f44810ab0f 100644 --- a/ApplicationLibCode/UserInterface/RiuPlotWidget.h +++ b/ApplicationLibCode/UserInterface/RiuPlotWidget.h @@ -183,6 +183,8 @@ public: virtual std::pair findClosestCurve( const QPoint& pos, double& distanceToClick ) const = 0; + virtual void updateZoomDependentCurveProperties(); + protected: void updateOverlayFrameLayout(); diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp index 551b3c72b4..18d1132f76 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include @@ -202,8 +204,7 @@ void RiuQtChartsPlotCurve::setSamplesInPlot( const std::vector& xValues, CAF_ASSERT( xValues.size() == yValues.size() ); - QtCharts::QLineSeries* line = lineSeries(); - QtCharts::QScatterSeries* scatter = scatterSeries(); + QtCharts::QLineSeries* line = lineSeries(); QVector values( static_cast( xValues.size() ) ); @@ -213,7 +214,88 @@ void RiuQtChartsPlotCurve::setSamplesInPlot( const std::vector& xValues, } line->replace( values ); - scatter->replace( values ); + + updateScatterSeries(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQtChartsPlotCurve::updateScatterSeries() +{ + double minX = std::numeric_limits::max(); + double maxX = -std::numeric_limits::max(); + + QVector points = lineSeries()->pointsVector(); + + auto axes = lineSeries()->attachedAxes(); + bool foundAxis = false; + for ( auto axis : axes ) + { + if ( axis->orientation() == Qt::Orientation::Horizontal ) + { + QtCharts::QValueAxis* valueAxis = dynamic_cast( axis ); + QtCharts::QDateTimeAxis* dateTimeAxis = dynamic_cast( axis ); + if ( valueAxis ) + { + minX = valueAxis->min(); + maxX = valueAxis->max(); + foundAxis = true; + } + else if ( dateTimeAxis ) + { + minX = dateTimeAxis->min().toMSecsSinceEpoch(); + maxX = dateTimeAxis->max().toMSecsSinceEpoch(); + foundAxis = true; + } + } + } + + if ( !foundAxis ) + { + for ( auto p : points ) + { + minX = std::min( minX, p.x() ); + maxX = std::max( maxX, p.x() ); + } + } + + QVector scatterValues; + if ( !points.empty() ) + { + double range = maxX - minX; + + double displaySize = 1400; + if ( m_plotWidget && m_plotWidget->qtChart() ) + { + // Use the max size since plot area can be small before the widget is shown + displaySize = std::max( displaySize, m_plotWidget->qtChart()->plotArea().width() ); + } + + double rangePerPixel = range / displaySize; + + double skipDistance = rangePerPixel * m_symbolSkipPixelDistance; + + // Always have symbol on first point + scatterValues << points[0]; + + int lastDrawnIndex = 0; + for ( int i = 1; i < static_cast( points.size() ); i++ ) + { + // Skip points until skip distance is reached + double diff = points[i].x() - points[lastDrawnIndex].x(); + + // Always add last point. + bool isLastPoint = i == points.size() - 1; + if ( diff > skipDistance || isLastPoint ) + { + scatterValues << points[i]; + lastDrawnIndex = i; + } + } + } + + scatterSeries()->replace( scatterValues ); } //-------------------------------------------------------------------------------------------------- @@ -255,8 +337,8 @@ void RiuQtChartsPlotCurve::setXAxis( RiuPlotAxis axis ) m_axisX = axis; if ( m_plotWidget ) { - m_plotWidget->setXAxis( axis, lineSeries() ); - m_plotWidget->setXAxis( axis, scatterSeries() ); + m_plotWidget->setXAxis( axis, lineSeries(), this ); + m_plotWidget->setXAxis( axis, scatterSeries(), this ); } } @@ -268,8 +350,8 @@ void RiuQtChartsPlotCurve::setYAxis( RiuPlotAxis axis ) m_axisY = axis; if ( m_plotWidget ) { - m_plotWidget->setYAxis( axis, lineSeries() ); - m_plotWidget->setYAxis( axis, scatterSeries() ); + m_plotWidget->setYAxis( axis, lineSeries(), this ); + m_plotWidget->setYAxis( axis, scatterSeries(), this ); } } @@ -335,8 +417,8 @@ void RiuQtChartsPlotCurve::setVisibleInLegend( bool isVisibleInLegend ) CAF_ASSERT( m_plotWidget->qtChart() ); CAF_ASSERT( m_plotWidget->qtChart()->legend() ); - // The markers can be set visible independent to the visibility state of the containing legend. Use the visibility - // state of the legend to override the visibility flag + // The markers can be set visible independent to the visibility state of the containing legend. Use the + // visibility state of the legend to override the visibility flag if ( !m_plotWidget->qtChart()->legend()->isAttachedToChart() ) isVisibleInLegend = false; if ( !m_plotWidget->qtChart()->legend()->isVisible() ) isVisibleInLegend = false; @@ -395,6 +477,7 @@ void RiuQtChartsPlotCurve::setSymbol( RiuPlotCurveSymbol* symbol ) if ( scatterSeries() ) { qtChartsSymbol->applyToScatterSeries( scatterSeries() ); + updateScatterSeries(); } } else @@ -435,3 +518,11 @@ QPixmap RiuQtChartsPlotCurve::legendIcon( const QSizeF& iconSize ) const { return QPixmap(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQtChartsPlotCurve::axisRangeChanged() +{ + updateScatterSeries(); +} diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h index 1752f1cbd3..e5d9115871 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h @@ -32,8 +32,9 @@ class RiuPlotCurveSymbol; //================================================================================================== // //================================================================================================== -class RiuQtChartsPlotCurve : public RiuPlotCurve +class RiuQtChartsPlotCurve : public QObject, public RiuPlotCurve { + Q_OBJECT public: explicit RiuQtChartsPlotCurve( RimPlotCurve* ownerRimCurve, const QString& title = QString() ); ~RiuQtChartsPlotCurve() override; @@ -77,6 +78,11 @@ public: RiuPlotCurveSymbol* createSymbol( RiuPlotCurveSymbol::PointSymbolEnum symbol ) const override; + void updateScatterSeries(); + +public slots: + void axisRangeChanged(); + private: void setSamplesInPlot( const std::vector&, const std::vector& ) override; diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp index bf95673a3e..44396f14fc 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp @@ -612,6 +612,18 @@ void RiuQtChartsPlotWidget::replot() qtChart()->update(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQtChartsPlotWidget::updateZoomDependentCurveProperties() +{ + for ( auto it : m_scatterSeriesMap ) + { + auto plotCurve = dynamic_cast( it.first ); + if ( plotCurve ) plotCurve->updateScatterSeries(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -782,22 +794,24 @@ void RiuQtChartsPlotWidget::attach( RiuPlotCurve* plotCurve, RiuPlotAxis xAxis, RiuPlotAxis yAxis ) { - auto addToChart = [this]( std::map& curveSeriesMap, - auto plotCurve, - auto series, - auto xAxis, - auto yAxis ) { + auto addToChart = [this]( std::map& curveSeriesMap, + auto plotCurve, + auto series, + auto xAxis, + auto yAxis, + RiuQtChartsPlotCurve* qtChartsPlotCurve ) { if ( !series->chart() ) { curveSeriesMap[plotCurve] = series; qtChart()->addSeries( series ); - setXAxis( xAxis, series ); - setXAxis( yAxis, series ); + setXAxis( xAxis, series, qtChartsPlotCurve ); + setYAxis( yAxis, series, qtChartsPlotCurve ); } }; - addToChart( m_lineSeriesMap, plotCurve, lineSeries, xAxis, yAxis ); - addToChart( m_scatterSeriesMap, plotCurve, scatterSeries, xAxis, yAxis ); + auto qtChartsPlotCurve = dynamic_cast( plotCurve ); + addToChart( m_lineSeriesMap, plotCurve, lineSeries, xAxis, yAxis, qtChartsPlotCurve ); + addToChart( m_scatterSeriesMap, plotCurve, scatterSeries, xAxis, yAxis, qtChartsPlotCurve ); } //-------------------------------------------------------------------------------------------------- @@ -805,7 +819,7 @@ void RiuQtChartsPlotWidget::attach( RiuPlotCurve* plotCurve, //-------------------------------------------------------------------------------------------------- QtCharts::QAbstractSeries* RiuQtChartsPlotWidget::getLineSeries( const RiuPlotCurve* plotCurve ) const { - auto series = m_lineSeriesMap.find( plotCurve ); + auto series = m_lineSeriesMap.find( const_cast( plotCurve ) ); if ( series != m_lineSeriesMap.end() ) return series->second; else @@ -817,7 +831,7 @@ QtCharts::QAbstractSeries* RiuQtChartsPlotWidget::getLineSeries( const RiuPlotCu //-------------------------------------------------------------------------------------------------- QtCharts::QAbstractSeries* RiuQtChartsPlotWidget::getScatterSeries( const RiuPlotCurve* plotCurve ) const { - auto series = m_scatterSeriesMap.find( plotCurve ); + auto series = m_scatterSeriesMap.find( const_cast( plotCurve ) ); if ( series != m_scatterSeriesMap.end() ) return series->second; else @@ -846,17 +860,17 @@ void RiuQtChartsPlotWidget::detachItems( RiuPlotWidget::PlotItemType plotItemTyp //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQtChartsPlotWidget::setXAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series ) +void RiuQtChartsPlotWidget::setXAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series, RiuQtChartsPlotCurve* plotCurve ) { - attachSeriesToAxis( axis, series ); + attachSeriesToAxis( axis, series, plotCurve ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQtChartsPlotWidget::setYAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series ) +void RiuQtChartsPlotWidget::setYAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series, RiuQtChartsPlotCurve* plotCurve ) { - attachSeriesToAxis( axis, series ); + attachSeriesToAxis( axis, series, plotCurve ); } //-------------------------------------------------------------------------------------------------- @@ -873,7 +887,9 @@ void RiuQtChartsPlotWidget::ensureAxisIsCreated( RiuPlotAxis axis ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQtChartsPlotWidget::attachSeriesToAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series ) +void RiuQtChartsPlotWidget::attachSeriesToAxis( RiuPlotAxis axis, + QtCharts::QAbstractSeries* series, + RiuQtChartsPlotCurve* plotCurve ) { // Make sure the axis we are about to set exists. ensureAxisIsCreated( axis ); @@ -896,6 +912,14 @@ void RiuQtChartsPlotWidget::attachSeriesToAxis( RiuPlotAxis axis, QtCharts::QAbs if ( qobject_cast( newAxis ) || qobject_cast( newAxis ) ) { connect( newAxis, SIGNAL( rangeChanged( double, double ) ), this, SLOT( axisRangeChanged() ), Qt::UniqueConnection ); + if ( plotCurve ) + { + connect( newAxis, + SIGNAL( rangeChanged( double, double ) ), + plotCurve, + SLOT( axisRangeChanged() ), + Qt::UniqueConnection ); + } } else if ( qobject_cast( newAxis ) ) { @@ -904,6 +928,14 @@ void RiuQtChartsPlotWidget::attachSeriesToAxis( RiuPlotAxis axis, QtCharts::QAbs this, SLOT( axisRangeChanged() ), Qt::UniqueConnection ); + if ( plotCurve ) + { + connect( newAxis, + SIGNAL( rangeChanged( QDateTime, QDateTime ) ), + plotCurve, + SLOT( axisRangeChanged() ), + Qt::UniqueConnection ); + } } } } diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h index ed124346fd..6cf00b0f25 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h @@ -34,6 +34,7 @@ class RiaPlotWindowRedrawScheduler; class RimPlot; class RiuPlotCurve; +class RiuQtChartsPlotCurve; class QEvent; class QLabel; @@ -165,8 +166,8 @@ public: QtCharts::QAbstractSeries* getLineSeries( const RiuPlotCurve* plotCurve ) const; QtCharts::QAbstractSeries* getScatterSeries( const RiuPlotCurve* plotCurve ) const; - void setXAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series ); - void setYAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series ); + void setXAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series, RiuQtChartsPlotCurve* plotCurve ); + void setYAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series, RiuQtChartsPlotCurve* plotCurve ); const QColor& backgroundColor() const override; @@ -174,8 +175,10 @@ public: std::pair findClosestCurve( const QPoint& pos, double& distanceToClick ) const override; + void updateZoomDependentCurveProperties() override; + protected: - void attachSeriesToAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series ); + void attachSeriesToAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series, RiuQtChartsPlotCurve* plotCurve ); void resizeEvent( QResizeEvent* event ) override; void keyPressEvent( QKeyEvent* event ) override; @@ -217,6 +220,6 @@ private: std::map m_axesEnabled; std::map m_axesAutoScale; - std::map m_lineSeriesMap; - std::map m_scatterSeriesMap; + std::map m_lineSeriesMap; + std::map m_scatterSeriesMap; };