From 52d2eed98bbab4846212e7cf58dc1d99521b8853 Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Wed, 13 Mar 2019 10:16:46 +0100 Subject: [PATCH] Fix log axis crash in Grid Cross Plot and refactor log axis range code --- ApplicationCode/Application/RiaDefines.cpp | 8 ++ ApplicationCode/Application/RiaDefines.h | 1 + .../GridCrossPlots/RimGridCrossPlot.cpp | 61 +++++++++++-- .../GridCrossPlots/RimGridCrossPlot.h | 6 +- .../RimGridCrossPlotCurveSet.cpp | 60 +++++++++++++ .../GridCrossPlots/RimGridCrossPlotCurveSet.h | 5 ++ .../ProjectDataModel/RimEclipseCellColors.cpp | 3 +- .../RimPlotAxisProperties.cpp | 85 ++++++++++--------- .../ProjectDataModel/RimPlotAxisProperties.h | 16 ++-- .../Summary/RimSummaryPlot.cpp | 11 +-- 10 files changed, 186 insertions(+), 70 deletions(-) diff --git a/ApplicationCode/Application/RiaDefines.cpp b/ApplicationCode/Application/RiaDefines.cpp index bd42aabda6..01fc5260ae 100644 --- a/ApplicationCode/Application/RiaDefines.cpp +++ b/ApplicationCode/Application/RiaDefines.cpp @@ -464,6 +464,14 @@ double RiaDefines::minimumDefaultValuePlot() return -10.0; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RiaDefines::minimumDefaultLogValuePlot() +{ + return 1.0; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/RiaDefines.h b/ApplicationCode/Application/RiaDefines.h index 5c2de20d28..80fa0330c7 100644 --- a/ApplicationCode/Application/RiaDefines.h +++ b/ApplicationCode/Application/RiaDefines.h @@ -135,6 +135,7 @@ namespace RiaDefines }; double minimumDefaultValuePlot(); + double minimumDefaultLogValuePlot(); double maximumDefaultValuePlot(); enum PhaseType { diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp index 2462cfe60f..24ee533aba 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp @@ -269,7 +269,7 @@ void RimGridCrossPlot::detachAllCurves() //-------------------------------------------------------------------------------------------------- void RimGridCrossPlot::updateAxisScaling() { - updateAxisDisplay(); + loadDataAndUpdate(); } //-------------------------------------------------------------------------------------------------- @@ -379,13 +379,11 @@ void RimGridCrossPlot::onLoadDataAndUpdate() for (auto curveSet : m_crossPlotCurveSets) { curveSet->loadDataAndUpdate(false); + curveSet->updateConnectedEditors(); } updateCurveNamesAndPlotTitle(); - updateAllRequiredEditors(); - - updatePlot(); - + updatePlot(); } //-------------------------------------------------------------------------------------------------- @@ -542,7 +540,7 @@ void RimGridCrossPlot::swapAxes() } loadDataAndUpdate(); - + updateAxisDisplay(); } @@ -574,7 +572,6 @@ QString RimGridCrossPlot::asciiDataForPlotExport(int curveSetIndex) const formatter.setTableRowLineAppendText(""); formatter.setColumnSpacing(3); - m_crossPlotCurveSets[curveSetIndex]->exportFormattedData(formatter); formatter.tableCompleted(); return asciiData; @@ -593,6 +590,22 @@ RiuGridCrossQwtPlot* RimGridCrossPlot::qwtPlot() const return m_qwtPlot; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::isXAxisLogarithmic() const +{ + return m_xAxisProperties->isLogarithmicScaleEnabled(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::isYAxisLogarithmic() const +{ + return m_yAxisProperties->isLogarithmicScaleEnabled(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -691,7 +704,17 @@ void RimGridCrossPlot::updateAxisInQwt(RiaDefines::PlotAxis axisType) if (axisProperties->isAutoZoom()) { - m_qwtPlot->setAxisAutoScale(qwtAxisId); + std::vector plotCurves = visibleQwtCurves(); + + double min, max; + RimPlotAxisLogRangeCalculator logRangeCalculator(qwtAxisId, plotCurves); + logRangeCalculator.computeAxisRange(&min, &max); + if (axisProperties->isAxisInverted()) + { + std::swap(min, max); + } + + m_qwtPlot->setAxisScale(qwtAxisId, min, max); } else { @@ -750,6 +773,28 @@ void RimGridCrossPlot::updateAxisFromQwt(RiaDefines::PlotAxis axisType) axisProperties->updateConnectedEditors(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGridCrossPlot::visibleQwtCurves() const +{ + std::vector plotCurves; + for (auto curveSet : m_crossPlotCurveSets) + { + if (curveSet->isChecked()) + { + for (auto curve : curveSet->curves()) + { + if (curve->isCurveVisible()) + { + plotCurves.push_back(curve->qwtPlotCurve()); + } + } + } + } + return plotCurves; +} + //-------------------------------------------------------------------------------------------------- /// Name Configuration /// diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h index 0b049fd64e..97870d774a 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h @@ -74,6 +74,8 @@ public: QString asciiTitleForPlotExport(int curveSetIndex) const; QString asciiDataForPlotExport(int curveSetIndex) const; RiuGridCrossQwtPlot* qwtPlot() const; + bool isXAxisLogarithmic() const; + bool isYAxisLogarithmic() const; public: // Rim2dPlotInterface overrides @@ -96,13 +98,13 @@ protected: bool* useOptionsOnly) override; void updatePlot(); - void updateCurveNames(); QString xAxisParameterString() const; QString yAxisParameterString() const; void updateAxisInQwt(RiaDefines::PlotAxis axisType); void updateAxisFromQwt(RiaDefines::PlotAxis axisType); + std::vector visibleQwtCurves() const; private: caf::PdmField m_showLegend; @@ -115,7 +117,7 @@ private: caf::PdmChildArrayField m_crossPlotCurveSets; QPointer m_qwtPlot; - + }; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp index a3c384e73e..6468afe615 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp @@ -406,6 +406,10 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot) RigEclipseCrossPlotResult result = RigEclipseCrossPlotDataExtractor::extract( eclipseCase->eclipseCaseData(), m_timeStep(), xAddress, yAddress, m_grouping(), groupAddress, timeStepCellVisibilityMap); + if (isXAxisLogarithmic() || isYAxisLogarithmic()) + { + filterInvalidCurveValues(&result); + } createCurves(result); if (updateParentPlot) @@ -877,6 +881,26 @@ void RimGridCrossPlotCurveSet::exportFormattedData(RifEclipseDataTableFormatter& } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotCurveSet::isXAxisLogarithmic() const +{ + RimGridCrossPlot* parent = nullptr; + firstAncestorOrThisOfTypeAsserted(parent); + return parent->isXAxisLogarithmic(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotCurveSet::isYAxisLogarithmic() const +{ + RimGridCrossPlot* parent = nullptr; + firstAncestorOrThisOfTypeAsserted(parent); + return parent->isYAxisLogarithmic(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1001,6 +1025,42 @@ bool RimGridCrossPlotCurveSet::hasMultipleTimeSteps() const } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurveSet::filterInvalidCurveValues(RigEclipseCrossPlotResult* result) +{ + bool xLog = isXAxisLogarithmic(); + bool yLog = isYAxisLogarithmic(); + + if (xLog || yLog) + { + + RigEclipseCrossPlotResult validResult; + for (size_t i = 0; i < result->xValues.size(); ++i) + { + double xValue = result->xValues[i]; + double yValue = result->yValues[i]; + bool invalid = (xLog && xValue <= 0.0) || (yLog && yValue <= 0.0); + if (!invalid) + { + validResult.xValues.push_back(xValue); + validResult.yValues.push_back(yValue); + if (i < result->groupValuesContinuous.size()) + { + validResult.groupValuesContinuous.push_back(result->groupValuesContinuous[i]); + } + if (i < result->groupValuesDiscrete.size()) + { + validResult.groupValuesDiscrete.push_back(result->groupValuesDiscrete[i]); + } + } + } + + *result = validResult; + } +} + CAF_PDM_SOURCE_INIT(RimGridCrossPlotCurveSetNameConfig, "RimGridCrossPlotCurveSetNameConfig"); //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h index d3667519b4..e4d6ea13ed 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h @@ -117,6 +117,9 @@ public: void swapAxisProperties(bool updatePlot); void exportFormattedData(RifEclipseDataTableFormatter& formatter) const; + bool isXAxisLogarithmic() const; + bool isYAxisLogarithmic() const; + protected: void initAfterRead() override; void onLoadDataAndUpdate(bool updateParentPlot); @@ -139,6 +142,7 @@ protected: void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; bool hasMultipleTimeSteps() const; + void filterInvalidCurveValues(RigEclipseCrossPlotResult* result); private: caf::PdmPtrField m_case; @@ -154,4 +158,5 @@ private: caf::PdmChildArrayField m_crossPlotCurves; std::map m_groupedResults; + }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp index 0f9831067e..1ea696aae3 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp @@ -239,12 +239,11 @@ void RimEclipseCellColors::uiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering //-------------------------------------------------------------------------------------------------- void RimEclipseCellColors::setReservoirView(RimEclipseView* ownerReservoirView) { + m_reservoirView = ownerReservoirView; if (ownerReservoirView) { this->setEclipseCase(ownerReservoirView->eclipseCase()); } - - m_reservoirView = ownerReservoirView; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp index c5c761d97b..265bd8231e 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp @@ -26,6 +26,8 @@ #include "cafPdmUiSliderEditor.h" +#include "cvfVector2.h" + #include #include @@ -373,32 +375,32 @@ caf::PdmFieldHandle* RimPlotAxisProperties::objectToggleField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimPlotAxisRangeCalculator::RimPlotAxisRangeCalculator(QwtPlot::Axis axis, - const std::vector& qwtCurves, - const std::vector& axisValuesForAllCurves) - : m_singleCurves(qwtCurves) - , m_axisValuesForAllCurves(axisValuesForAllCurves) +RimPlotAxisLogRangeCalculator::RimPlotAxisLogRangeCalculator(QwtPlot::Axis axis, + const std::vector& qwtCurves) + : m_axis(axis) + , m_curves(qwtCurves) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimPlotAxisRangeCalculator::computeAxisRange(double* min, double* max) const +void RimPlotAxisLogRangeCalculator::computeAxisRange(double* minPositive, double* max) const { - double minValue = HUGE_VAL; - double maxValue = -HUGE_VAL; + double minPosValue = HUGE_VAL; + double maxValue = -HUGE_VAL; - for (QwtPlotCurve* curve : m_singleCurves) + for (const QwtPlotCurve* curve : m_curves) { - double minCurveValue = HUGE_VAL; - double maxCurveValue = -HUGE_VAL; + double minPosCurveValue = HUGE_VAL; + double maxCurveValue = -HUGE_VAL; - if (curveValueRange(curve, &minCurveValue, &maxCurveValue)) + if (curveValueRange(curve, &minPosCurveValue, &maxCurveValue)) { - if (minCurveValue < minValue) + if (minPosCurveValue < minPosValue) { - minValue = minCurveValue; + CVF_ASSERT(minPosCurveValue > 0.0); + minPosValue = minPosCurveValue; } if (maxCurveValue > maxValue) @@ -408,33 +410,20 @@ void RimPlotAxisRangeCalculator::computeAxisRange(double* min, double* max) cons } } - if (minValue == HUGE_VAL) + if (minPosValue == HUGE_VAL) { - minValue = RiaDefines::minimumDefaultValuePlot(); - maxValue = RiaDefines::maximumDefaultValuePlot(); + minPosValue = RiaDefines::minimumDefaultLogValuePlot(); + maxValue = RiaDefines::maximumDefaultValuePlot(); } - - // For logarithmic auto scaling, compute positive curve value closest to zero and use - // this value as the plot visible minimum - - double pos = HUGE_VAL; - double neg = -HUGE_VAL; - - RigStatisticsCalculator::posNegClosestToZero(m_axisValuesForAllCurves, pos, neg); - - if (pos != HUGE_VAL) - { - minValue = pos; - } - - *min = minValue; - *max = maxValue; + + *minPositive = minPosValue; + *max = maxValue; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimPlotAxisRangeCalculator::curveValueRange(const QwtPlotCurve* qwtCurve, double* min, double* max) const +bool RimPlotAxisLogRangeCalculator::curveValueRange(const QwtPlotCurve* qwtCurve, double* minPositive, double* max) const { if (!qwtCurve) return false; @@ -443,15 +432,31 @@ bool RimPlotAxisRangeCalculator::curveValueRange(const QwtPlotCurve* qwtCurve, d return false; } - if (m_axis == QwtPlot::xBottom || m_axis == QwtPlot::xTop) + float minPosF = std::numeric_limits::infinity(); + float maxF = -std::numeric_limits::infinity(); + + int axisValueIndex = 0; + if (m_axis == QwtPlot::yLeft || m_axis == QwtPlot::yRight) { - *min = qwtCurve->minXValue(); - *max = qwtCurve->maxXValue(); + axisValueIndex = 1; } - else + + for (size_t i = 0; i < qwtCurve->dataSize(); ++i) { - *min = qwtCurve->minYValue(); - *max = qwtCurve->maxYValue(); + QPointF sample = qwtCurve->sample((int) i); + cvf::Vec2f vec(sample.x(), sample.y()); + float value = vec[axisValueIndex]; + if (value == HUGE_VALF) continue; + + maxF = std::max(maxF, value); + if (value > 0.0f && value < minPosF) + { + minPosF = value; + } } + + *minPositive = minPosF; + *max = maxF; + return true; } diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h index 66ac22b7a2..ce1f665aa1 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h @@ -120,20 +120,18 @@ class QwtPlotCurve; /// /// //================================================================================================== -class RimPlotAxisRangeCalculator +class RimPlotAxisLogRangeCalculator { public: - RimPlotAxisRangeCalculator(QwtPlot::Axis axis, - const std::vector& qwtCurves, - const std::vector& axisValuesForAllCurves); + RimPlotAxisLogRangeCalculator(QwtPlot::Axis axis, + const std::vector& qwtCurves); - void computeAxisRange(double* min, double* max) const; + void computeAxisRange(double* minPositive, double* max) const; private: - bool curveValueRange(const QwtPlotCurve* qwtCurve, double* min, double* max) const; + bool curveValueRange(const QwtPlotCurve* qwtCurve, double* minPositive, double* max) const; private: - QwtPlot::Axis m_axis; - const std::vector m_singleCurves; - const std::vector m_axisValuesForAllCurves; + QwtPlot::Axis m_axis; + const std::vector m_curves; }; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp index 171bb7e502..30cb9a63cc 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp @@ -635,32 +635,25 @@ void RimSummaryPlot::updateZoomForAxis(RiaDefines::PlotAxis plotAxis) { if (yAxisProps->isLogarithmicScaleEnabled) { - std::vector yValues; - std::vector plotCurves; + std::vector plotCurves; for (RimSummaryCurve* c : visibleSummaryCurvesForAxis(plotAxis)) { - std::vector curveValues = c->valuesY(); - yValues.insert(yValues.end(), curveValues.begin(), curveValues.end()); plotCurves.push_back(c->qwtPlotCurve()); } for (RimGridTimeHistoryCurve* c : visibleTimeHistoryCurvesForAxis(plotAxis)) { - std::vector curveValues = c->yValues(); - yValues.insert(yValues.end(), curveValues.begin(), curveValues.end()); plotCurves.push_back(c->qwtPlotCurve()); } for (RimAsciiDataCurve* c : visibleAsciiDataCurvesForAxis(plotAxis)) { - std::vector curveValues = c->yValues(); - yValues.insert(yValues.end(), curveValues.begin(), curveValues.end()); plotCurves.push_back(c->qwtPlotCurve()); } double min, max; - RimPlotAxisRangeCalculator calc(QwtPlot::yLeft, plotCurves, yValues); + RimPlotAxisLogRangeCalculator calc(QwtPlot::yLeft, plotCurves); calc.computeAxisRange(&min, &max); if (yAxisProps->isAxisInverted())