mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
Axis range and auto-zoom setters now schedule the editor update instead of performing it immediately. Every immediate update rebuilds the tags of the whole project tree, and zoom-all releases the range and re-enables auto zoom for every axis of every subplot. Scheduling also avoids deleting the tag whose clicked signal is still being emitted from onPinnedTagClicked(). Remove the m_isAutoZoom branches in fieldChangedByUi(). The field is not part of any UI ordering, and both orderings end with skipRemainingFields(), so the branches were unreachable. Comments referring to a "Set Range Automatically" checkbox are updated accordingly. The pinned tag no longer reuses pinned.svg, which is also the Quick Access dock icon and must keep following the widget palette. The gray tag variant lives in PinnedAxisRange.svg. Zoom All is an explicit request for automatic ranges, but only summary plots released the user defined range. Histogram, grid cross, VFP and analysis plots share RimPlotAxisProperties and set the range as user defined when a min or max is typed, so Zoom All left them with a stale pinned tag and permanently blocked enableAutoValueMinMax(). Release the range for every axis owned by the window in RimViewWindow instead, which makes the summary specific overrides redundant.
1975 lines
74 KiB
C++
1975 lines
74 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2021 Equinor ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RimSummaryMultiPlot.h"
|
|
|
|
#include "RiaApplication.h"
|
|
#include "RiaNumericalTools.h"
|
|
#include "RiaPlotDefines.h"
|
|
#include "RiaPreferences.h"
|
|
#include "RiaQDateTimeTools.h"
|
|
#include "RiaTimeTTools.h"
|
|
#include "Summary/RiaSummaryAddressAnalyzer.h"
|
|
#include "Summary/RiaSummaryAddressModifier.h"
|
|
#include "Summary/RiaSummaryPlotTools.h"
|
|
#include "Summary/RiaSummaryStringTools.h"
|
|
|
|
#include "PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.h"
|
|
#include "PlotBuilderCommands/RicAppendSummaryPlotsForSummaryAddressesFeature.h"
|
|
#include "PlotBuilderCommands/RicAppendSummaryPlotsForSummaryCasesFeature.h"
|
|
|
|
#include "RifEclEclipseSummary.h"
|
|
#include "RifEclipseRftAddress.h"
|
|
#include "RifEclipseSummaryAddress.h"
|
|
|
|
#include "RimAnnotationLineAppearance.h"
|
|
#include "RimEnsembleCurveSet.h"
|
|
#include "RimMainPlotCollection.h"
|
|
#include "RimMultiPlotCollection.h"
|
|
#include "RimMultipleSummaryPlotNameHelper.h"
|
|
#include "RimPlotAxisProperties.h"
|
|
#include "RimSummaryAddress.h"
|
|
#include "RimSummaryAddressCollection.h"
|
|
#include "RimSummaryCase.h"
|
|
#include "RimSummaryCurve.h"
|
|
#include "RimSummaryEnsemble.h"
|
|
#include "RimSummaryMultiPlotCollection.h"
|
|
#include "RimSummaryPlot.h"
|
|
#include "RimSummaryPlotControls.h"
|
|
#include "RimSummaryPlotNameHelper.h"
|
|
#include "RimSummaryPlotReadOut.h"
|
|
#include "RimSummaryPlotSourceStepping.h"
|
|
#include "RimSummaryTimeAxisProperties.h"
|
|
|
|
#include "RiuPlotMainWindowTools.h"
|
|
#include "RiuQwtPlotWidget.h"
|
|
#include "RiuSummaryMultiPlotBook.h"
|
|
#include "RiuSummaryVectorSelectionUi.h"
|
|
|
|
#include "cafPdmObjectScriptingCapability.h"
|
|
#include "cafPdmUiButton.h"
|
|
#include "cafPdmUiCheckBoxEditor.h"
|
|
#include "cafPdmUiComboBoxEditor.h"
|
|
#include "cafPdmUiLabelEditor.h"
|
|
#include "cafPdmUiNumberFormat.h"
|
|
#include "cafPdmUiTreeOrdering.h"
|
|
#include "cafPdmUiTreeSelectionEditor.h"
|
|
#include "cafSelectionManager.h"
|
|
|
|
#include "qwt_scale_engine.h"
|
|
|
|
#include <QKeyEvent>
|
|
|
|
#include <cmath>
|
|
|
|
namespace caf
|
|
{
|
|
template <>
|
|
void AppEnum<RimSummaryMultiPlot::AxisRangeAggregation>::setUp()
|
|
{
|
|
addItem( RimSummaryMultiPlot::AxisRangeAggregation::NONE, "NONE", "Per Sub Plot" );
|
|
addItem( RimSummaryMultiPlot::AxisRangeAggregation::SUB_PLOTS, "SUB_PLOTS", "All Sub Plots" );
|
|
addItem( RimSummaryMultiPlot::AxisRangeAggregation::WELLS, "WELLS", "All Wells" );
|
|
addItem( RimSummaryMultiPlot::AxisRangeAggregation::REGIONS, "REGIONS", "All Regions" );
|
|
addItem( RimSummaryMultiPlot::AxisRangeAggregation::REALIZATIONS, "REALIZATIONS", "All Realizations" );
|
|
setDefault( RimSummaryMultiPlot::AxisRangeAggregation::NONE );
|
|
}
|
|
} // namespace caf
|
|
|
|
CAF_PDM_SOURCE_INIT( RimSummaryMultiPlot, "MultiSummaryPlot" );
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setLayoutInfo( RimSummaryPlot* summaryPlot, int row, int col )
|
|
{
|
|
m_gridLayoutInfo[summaryPlot] = std::make_pair( row, col );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::clearLayoutInfo()
|
|
{
|
|
m_gridLayoutInfo.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSummaryMultiPlot::RimSummaryMultiPlot()
|
|
{
|
|
CAF_PDM_InitScriptableObject( "Multi Summary Plot", ":/SummaryPlotLight16x16.png" );
|
|
setDeletable( true );
|
|
|
|
CAF_PDM_InitField( &m_autoPlotTitle, "AutoPlotTitle", true, "Auto Plot Title" );
|
|
CAF_PDM_InitField( &m_autoSubPlotTitle, "AutoSubPlotTitle", true, "Auto Sub Plot Title" );
|
|
|
|
CAF_PDM_InitField( &m_createPlotDuplicate, "DuplicatePlot", false, "", "", "Duplicate Plot" );
|
|
m_createPlotDuplicate.uiCapability()->setUiIconFromResourceString( ":/Copy.svg" );
|
|
|
|
CAF_PDM_InitField( &m_disableWheelZoom, "DisableWheelZoom", true, "", "", "Disable Mouse Wheel Zooming in Multi Summary Plot" );
|
|
m_disableWheelZoom.uiCapability()->setUiIconFromResourceString( ":/DisableZoom.png" );
|
|
|
|
CAF_PDM_InitField( &m_appendNextPlot, "AppendNextPlot", false, "", "", "Step Next and Add to New Plot" );
|
|
m_appendNextPlot.uiCapability()->setUiIconFromResourceString( ":/AppendNext.png" );
|
|
|
|
CAF_PDM_InitField( &m_appendPrevPlot, "AppendPrevPlot", false, "", "", "Step Previous and Add to New Plot" );
|
|
m_appendPrevPlot.uiCapability()->setUiIconFromResourceString( ":/AppendPrev.png" );
|
|
|
|
CAF_PDM_InitField( &m_appendNextCurve, "AppendNextCurve", false, "", "", "Step Next and Add Curve to Plot" );
|
|
m_appendNextCurve.uiCapability()->setUiIconFromResourceString( ":/AppendNextCurve.png" );
|
|
|
|
CAF_PDM_InitField( &m_appendPrevCurve, "AppendPrevCurve", false, "", "", "Step Previous and Add Curve to Plot" );
|
|
m_appendPrevCurve.uiCapability()->setUiIconFromResourceString( ":/AppendPrevCurve.png" );
|
|
|
|
CAF_PDM_InitField( &m_linkSubPlotAxes, "LinkSubPlotAxes", false, "Link Y Axes" );
|
|
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_linkSubPlotAxes );
|
|
CAF_PDM_InitField( &m_linkTimeAxis, "LinkTimeAxis", true, "Link Time Axis" );
|
|
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_linkTimeAxis );
|
|
CAF_PDM_InitField( &m_autoAdjustAppearance, "AutoAdjustAppearance", true, "Auto Plot Settings" );
|
|
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_autoAdjustAppearance );
|
|
CAF_PDM_InitField( &m_allow3DSelectionLink, "Allow3DSelectionLink", true, "Allow Well Selection from 3D View" );
|
|
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_allow3DSelectionLink );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_readOutSettings, "ReadOutSettings", "Read Out Settings" );
|
|
m_readOutSettings = new RimSummaryPlotReadOut;
|
|
m_readOutSettings.uiCapability()->setUiTreeChildrenHidden( true );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_goToCommonSettings, "GoToCommonSettings", "" );
|
|
m_goToCommonSettings.uiCapability()->setUiEditorTypeName( caf::PdmUiLabelEditor::uiEditorTypeName() );
|
|
m_goToCommonSettings.xmlCapability()->disableIO();
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_axisRangeAggregation, "AxisRangeAggregation", "Y Axis Range" );
|
|
|
|
CAF_PDM_InitField( &m_plotFilterYAxisThreshold, "PlotFilterYAxisThreshold", 0.0, "Y-Axis Filter Threshold" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_sourceStepping, "SourceStepping", "" );
|
|
|
|
m_sourceStepping = new RimSummaryPlotSourceStepping;
|
|
m_sourceStepping->setSourceSteppingObject( this );
|
|
m_sourceStepping.uiCapability()->setUiTreeChildrenHidden( true );
|
|
m_sourceStepping.xmlCapability()->disableIO();
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_defaultStepDimension, "DefaultStepDimension", "Default Step Dimension" );
|
|
m_defaultStepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::VECTOR;
|
|
m_defaultStepDimension.uiCapability()->setUiHidden( true );
|
|
|
|
m_nameHelper = std::make_unique<RimSummaryPlotNameHelper>();
|
|
|
|
setBottomMargin( 40 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSummaryMultiPlot::~RimSummaryMultiPlot()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::addPlot( RimPlot* plot )
|
|
{
|
|
auto* sumPlot = dynamic_cast<RimSummaryPlot*>( plot );
|
|
CAF_ASSERT( sumPlot != nullptr );
|
|
if ( sumPlot )
|
|
{
|
|
RimMultiPlot::addPlot( plot );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::insertPlot( RimPlot* plot, size_t index )
|
|
{
|
|
auto* sumPlot = dynamic_cast<RimSummaryPlot*>( plot );
|
|
CAF_ASSERT( sumPlot != nullptr );
|
|
if ( sumPlot )
|
|
{
|
|
sumPlot->axisChanged.connect( this, &RimSummaryMultiPlot::onSubPlotAxisChanged );
|
|
sumPlot->curvesChanged.connect( this, &RimSummaryMultiPlot::onSubPlotChanged );
|
|
sumPlot->titleChanged.connect( this, &RimSummaryMultiPlot::onSubPlotChanged );
|
|
sumPlot->axisChangedReloadRequired.connect( this, &RimSummaryMultiPlot::onSubPlotAxisReloadRequired );
|
|
sumPlot->autoTitleChanged.connect( this, &RimSummaryMultiPlot::onSubPlotAutoTitleChanged );
|
|
|
|
bool isMinMaxOverridden = m_axisRangeAggregation() != AxisRangeAggregation::NONE;
|
|
setAutoValueStatesForPlot( sumPlot, isMinMaxOverridden, m_autoAdjustAppearance() );
|
|
|
|
auto plots = summaryPlots();
|
|
if ( !plots.empty() && m_linkTimeAxis )
|
|
{
|
|
sumPlot->copyAxisPropertiesFromOther( RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM, *plots.front() );
|
|
}
|
|
|
|
RimMultiPlot::insertPlot( plot, index );
|
|
|
|
updateReadOutSettings();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::handleDroppedObjects( const std::vector<caf::PdmObjectHandle*>& objects )
|
|
{
|
|
if ( objects.empty() ) return;
|
|
|
|
std::vector<RimSummaryAddress*> addresses;
|
|
std::vector<RimSummaryAddressCollection*> addressCollections;
|
|
std::vector<RimSummaryCase*> cases;
|
|
std::vector<RimSummaryEnsemble*> ensembles;
|
|
|
|
for ( auto o : objects )
|
|
{
|
|
auto address = dynamic_cast<RimSummaryAddress*>( o );
|
|
if ( address ) addresses.push_back( address );
|
|
|
|
auto adrColl = dynamic_cast<RimSummaryAddressCollection*>( o );
|
|
if ( adrColl )
|
|
{
|
|
if ( objects.size() == 1 && adrColl->isFolder() )
|
|
{
|
|
// If a folder is selected, return all sub items in folder
|
|
auto childObjects = adrColl->subFolders();
|
|
addressCollections.insert( addressCollections.end(), childObjects.begin(), childObjects.end() );
|
|
}
|
|
else
|
|
addressCollections.push_back( adrColl );
|
|
}
|
|
|
|
auto summaryCase = dynamic_cast<RimSummaryCase*>( o );
|
|
if ( summaryCase ) cases.push_back( summaryCase );
|
|
auto ensemble = dynamic_cast<RimSummaryEnsemble*>( o );
|
|
if ( ensemble ) ensembles.push_back( ensemble );
|
|
}
|
|
|
|
RicAppendSummaryPlotsForSummaryAddressesFeature::appendPlotsForAddresses( this, addresses );
|
|
RicAppendSummaryPlotsForObjectsFeature::appendPlots( this, addressCollections );
|
|
RicAppendSummaryPlotsForObjectsFeature::appendPlots( this, cases, ensembles );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::removePlot( RimPlot* plot )
|
|
{
|
|
auto* sumPlot = dynamic_cast<RimSummaryPlot*>( plot );
|
|
CAF_ASSERT( sumPlot != nullptr );
|
|
if ( sumPlot )
|
|
{
|
|
RimMultiPlot::removePlot( plot );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::removePlotNoUpdate( RimPlot* plot )
|
|
{
|
|
auto* sumPlot = dynamic_cast<RimSummaryPlot*>( plot );
|
|
CAF_ASSERT( sumPlot != nullptr );
|
|
if ( sumPlot )
|
|
{
|
|
RimMultiPlot::removePlotNoUpdate( plot );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateAfterPlotRemove()
|
|
{
|
|
onPlotAdditionOrRemoval();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryCurve*> RimSummaryMultiPlot::curvesForStepping() const
|
|
{
|
|
std::vector<RimSummaryCurve*> curves;
|
|
|
|
for ( auto summaryPlot : summaryPlots() )
|
|
{
|
|
for ( auto curve : summaryPlot->curvesForStepping() )
|
|
{
|
|
curves.push_back( curve );
|
|
}
|
|
}
|
|
|
|
return curves;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimEnsembleCurveSet*> RimSummaryMultiPlot::curveSets() const
|
|
{
|
|
std::vector<RimEnsembleCurveSet*> curveSets;
|
|
|
|
for ( auto summaryPlot : summaryPlots() )
|
|
{
|
|
for ( auto curveSet : summaryPlot->curveSets() )
|
|
{
|
|
curveSets.push_back( curveSet );
|
|
}
|
|
}
|
|
|
|
return curveSets;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryCurve*> RimSummaryMultiPlot::allCurves() const
|
|
{
|
|
std::vector<RimSummaryCurve*> curves;
|
|
|
|
for ( auto summaryPlot : summaryPlots() )
|
|
{
|
|
for ( auto curve : summaryPlot->allCurves() )
|
|
{
|
|
curves.push_back( curve );
|
|
}
|
|
}
|
|
|
|
return curves;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::populateNameHelper( RimSummaryPlotNameHelper* nameHelper )
|
|
{
|
|
nameHelper->clear();
|
|
|
|
std::vector<RiaSummaryCurveAddress> addresses;
|
|
std::vector<RimSummaryCase*> sumCases;
|
|
std::vector<RimSummaryEnsemble*> ensembleCases;
|
|
|
|
for ( RimSummaryCurve* curve : allCurves() )
|
|
{
|
|
addresses.push_back( curve->curveAddress() );
|
|
sumCases.push_back( curve->summaryCaseY() );
|
|
}
|
|
|
|
for ( auto curveSet : curveSets() )
|
|
{
|
|
addresses.push_back( curveSet->curveAddress() );
|
|
ensembleCases.push_back( curveSet->summaryEnsemble() );
|
|
}
|
|
|
|
nameHelper->appendAddresses( addresses );
|
|
nameHelper->setSummaryCases( sumCases );
|
|
nameHelper->setEnsembleCases( ensembleCases );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
|
{
|
|
auto axesGroup = uiOrdering.addNewGroup( "Axes" );
|
|
axesGroup->add( &m_axisRangeAggregation );
|
|
axesGroup->add( &m_linkSubPlotAxes );
|
|
axesGroup->add( &m_linkTimeAxis );
|
|
axesGroup->add( &m_autoAdjustAppearance );
|
|
|
|
auto readOutGroup = uiOrdering.addNewGroup( "Mouse Cursor Readout" );
|
|
if ( m_readOutSettings == activeReadoutSettings() )
|
|
{
|
|
m_readOutSettings->uiOrdering( uiConfigName, *readOutGroup );
|
|
}
|
|
else
|
|
{
|
|
readOutGroup->add( &m_goToCommonSettings );
|
|
}
|
|
|
|
auto plotVisibilityFilterGroup = uiOrdering.addNewGroup( "Plot Visibility Filter" );
|
|
plotVisibilityFilterGroup->add( &m_plotFilterYAxisThreshold );
|
|
plotVisibilityFilterGroup->addNewButton( "Apply Filter", [this]() { updatePlotVisibility(); }, { .newRow = false } );
|
|
|
|
auto dataSourceGroup = uiOrdering.addNewGroup( "Data Source" );
|
|
dataSourceGroup->setCollapsedByDefault();
|
|
m_sourceStepping()->uiOrdering( uiConfigName, *dataSourceGroup );
|
|
|
|
if ( m_sourceStepping->stepDimension() == SourceSteppingDimension::WELL ) dataSourceGroup->add( &m_allow3DSelectionLink );
|
|
|
|
auto titlesGroup = uiOrdering.addNewGroup( "Main Plot Settings" );
|
|
titlesGroup->setCollapsedByDefault();
|
|
|
|
// If a checkbox is first in the group, it is not responding to mouse clicks. Set title as first element.
|
|
// https://github.com/OPM/ResInsight/issues/10321
|
|
titlesGroup->add( &m_plotWindowTitle );
|
|
titlesGroup->add( &m_autoPlotTitle );
|
|
titlesGroup->add( &m_showPlotWindowTitle );
|
|
titlesGroup->add( &m_titleFontSize );
|
|
|
|
auto subPlotSettingsGroup = uiOrdering.addNewGroup( "Sub Plot Settings" );
|
|
subPlotSettingsGroup->setCollapsedByDefault();
|
|
subPlotSettingsGroup->add( &m_autoSubPlotTitle );
|
|
subPlotSettingsGroup->add( &m_showIndividualPlotTitles );
|
|
subPlotSettingsGroup->add( &m_subTitleFontSize );
|
|
|
|
auto legendsGroup = uiOrdering.addNewGroup( "Legends" );
|
|
legendsGroup->setCollapsedByDefault();
|
|
legendsGroup->add( &m_showPlotLegends );
|
|
legendsGroup->add( &m_plotLegendsHorizontal );
|
|
legendsGroup->add( &m_legendPosition );
|
|
legendsGroup->add( &m_legendFontSize );
|
|
|
|
uiOrdering.skipRemainingFields( true );
|
|
|
|
updateReadOnlyState();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
|
{
|
|
if ( changedField == &m_autoPlotTitle || changedField == &m_autoSubPlotTitle )
|
|
{
|
|
onLoadDataAndUpdate();
|
|
updateLayout();
|
|
}
|
|
else if ( changedField == &m_linkTimeAxis )
|
|
{
|
|
updateTimeAxisRangesFromFirstTimePlot();
|
|
}
|
|
else if ( changedField == &m_linkSubPlotAxes )
|
|
{
|
|
if ( m_linkSubPlotAxes() )
|
|
{
|
|
// Set the range aggregation to all sub plots when linking. This will ensure that the ZoomAll operation works on all sub plots.
|
|
m_axisRangeAggregation = AxisRangeAggregation::SUB_PLOTS;
|
|
}
|
|
|
|
setAutoValueStates();
|
|
syncAxisRanges();
|
|
analyzePlotsAndAdjustAppearanceSettings();
|
|
zoomAll();
|
|
}
|
|
else if ( changedField == &m_axisRangeAggregation )
|
|
{
|
|
// The user has asked for a new computation of the Y axis range, release any user defined ranges
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
for ( auto axis : p->plotAxes( RimPlotAxisProperties::Orientation::VERTICAL ) )
|
|
{
|
|
axis->setRangeUserDefined( false );
|
|
}
|
|
}
|
|
|
|
setAutoValueStates();
|
|
syncAxisRanges();
|
|
analyzePlotsAndAdjustAppearanceSettings();
|
|
zoomAll();
|
|
}
|
|
else if ( changedField == &m_createPlotDuplicate )
|
|
{
|
|
m_createPlotDuplicate = false;
|
|
if ( auto plotCollection = RimMainPlotCollection::current()->summaryMultiPlotCollection() )
|
|
{
|
|
plotCollection->duplicatePlot( this );
|
|
}
|
|
}
|
|
else if ( changedField == &m_appendNextPlot )
|
|
{
|
|
m_appendNextPlot = false;
|
|
int stepDirection = 1;
|
|
appendSubPlotByStepping( stepDirection );
|
|
}
|
|
else if ( changedField == &m_appendPrevPlot )
|
|
{
|
|
m_appendPrevPlot = false;
|
|
int stepDirection = -1;
|
|
appendSubPlotByStepping( stepDirection );
|
|
}
|
|
else if ( changedField == &m_appendNextCurve )
|
|
{
|
|
m_appendNextCurve = false;
|
|
int stepDirection = 1;
|
|
appendCurveByStepping( stepDirection );
|
|
}
|
|
else if ( changedField == &m_appendPrevCurve )
|
|
{
|
|
m_appendPrevCurve = false;
|
|
int stepDirection = -1;
|
|
appendCurveByStepping( stepDirection );
|
|
}
|
|
else if ( changedField == &m_autoAdjustAppearance )
|
|
{
|
|
setAutoValueStates();
|
|
analyzePlotsAndAdjustAppearanceSettings();
|
|
}
|
|
else if ( changedField == &m_plotWindowTitle )
|
|
{
|
|
// If the user has changed the plot title, disable the auto plot title
|
|
// Workaround for https://github.com/OPM/ResInsight/issues/9681
|
|
|
|
m_autoPlotTitle = false;
|
|
}
|
|
|
|
RimMultiPlot::fieldChangedByUi( changedField, oldValue, newValue );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
|
|
{
|
|
if ( changedChildField == &m_readOutSettings )
|
|
{
|
|
updateReadOutSettings();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
|
{
|
|
if ( field == &m_goToCommonSettings )
|
|
{
|
|
if ( auto labelEditorAttribute = dynamic_cast<caf::PdmUiLabelEditorAttribute*>( attribute ) )
|
|
{
|
|
labelEditorAttribute->m_useWordWrap = true;
|
|
labelEditorAttribute->m_linkText = "Select <a href=\"dummy\">Summary Plots</a> to edit Common Readout Settings.";
|
|
labelEditorAttribute->m_linkActivatedCallback = []( const QString& link )
|
|
{
|
|
if ( auto plotCollection = RimMainPlotCollection::current()->summaryMultiPlotCollection() )
|
|
{
|
|
RiuPlotMainWindowTools::selectAsCurrentItem( plotCollection );
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updatePlotTitles()
|
|
{
|
|
if ( m_autoPlotTitle )
|
|
{
|
|
populateNameHelper( m_nameHelper.get() );
|
|
|
|
auto title = m_nameHelper->plotTitle();
|
|
|
|
if ( title.isEmpty() )
|
|
{
|
|
auto collections = RimMainPlotCollection::current()->summaryMultiPlotCollection();
|
|
|
|
size_t index = 0;
|
|
for ( auto p : collections->multiPlots() )
|
|
{
|
|
index++;
|
|
if ( p == this ) break;
|
|
}
|
|
|
|
title = QString( "Plot %1" ).arg( index );
|
|
}
|
|
|
|
setMultiPlotTitle( title );
|
|
}
|
|
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
if ( m_autoSubPlotTitle )
|
|
{
|
|
auto subPlotNameHelper = plot->plotTitleHelper();
|
|
|
|
// Disable auto plot title, as this is required to be able to include the information in the multi plot
|
|
// title
|
|
plot->enableAutoPlotTitle( false );
|
|
|
|
auto plotName = subPlotNameHelper->aggregatedPlotTitle( *m_nameHelper );
|
|
plot->setPlotTitleVisible( true );
|
|
plot->setDescription( plotName );
|
|
}
|
|
plot->updatePlotTitle();
|
|
}
|
|
|
|
if ( !m_viewer.isNull() ) m_viewer->scheduleTitleUpdate();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RimSummaryNameHelper* RimSummaryMultiPlot::nameHelper() const
|
|
{
|
|
return m_nameHelper.get();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setAutoPlotTitle( bool enable )
|
|
{
|
|
m_autoPlotTitle = enable;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setAutoSubPlotTitle( bool enable )
|
|
{
|
|
m_autoSubPlotTitle = enable;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryPlot*> RimSummaryMultiPlot::summaryPlots() const
|
|
{
|
|
std::vector<RimSummaryPlot*> typedPlots;
|
|
|
|
for ( auto plot : plots() )
|
|
{
|
|
auto summaryPlot = dynamic_cast<RimSummaryPlot*>( plot );
|
|
if ( summaryPlot ) typedPlots.push_back( summaryPlot );
|
|
}
|
|
|
|
return typedPlots;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryPlot*> RimSummaryMultiPlot::visibleSummaryPlots() const
|
|
{
|
|
std::vector<RimSummaryPlot*> visiblePlots;
|
|
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
if ( plot->showWindow() ) visiblePlots.push_back( plot );
|
|
}
|
|
|
|
return visiblePlots;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<caf::PdmFieldHandle*> RimSummaryMultiPlot::fieldsToShowInToolbar()
|
|
{
|
|
std::vector<caf::PdmFieldHandle*> toolBarFields;
|
|
|
|
toolBarFields.push_back( &m_disableWheelZoom );
|
|
|
|
auto& sourceObject = m_sourceStepping();
|
|
if ( sourceObject )
|
|
{
|
|
sourceObject->setSourceSteppingObject( steppingSourceObject() );
|
|
|
|
auto fields = sourceObject->fieldsToShowInToolbar();
|
|
toolBarFields.insert( std::end( toolBarFields ), std::begin( fields ), std::end( fields ) );
|
|
}
|
|
|
|
toolBarFields.push_back( &m_appendPrevPlot );
|
|
toolBarFields.push_back( &m_appendNextPlot );
|
|
|
|
toolBarFields.push_back( &m_appendPrevCurve );
|
|
toolBarFields.push_back( &m_appendNextCurve );
|
|
|
|
toolBarFields.push_back( &m_createPlotDuplicate );
|
|
|
|
auto multiFields = RimMultiPlot::fieldsToShowInToolbar();
|
|
toolBarFields.insert( std::end( toolBarFields ), std::begin( multiFields ), std::end( multiFields ) );
|
|
|
|
return toolBarFields;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimSummaryMultiPlot::handleGlobalKeyEvent( QKeyEvent* keyEvent )
|
|
{
|
|
bool isHandled = RimSummaryPlotControls::handleKeyEvents( m_sourceStepping(), keyEvent );
|
|
|
|
if ( !isHandled && isMouseCursorInsidePlot() )
|
|
{
|
|
if ( keyEvent->key() == Qt::Key_PageUp )
|
|
{
|
|
m_viewer->goToPrevPage();
|
|
return true;
|
|
}
|
|
|
|
if ( keyEvent->key() == Qt::Key_PageDown )
|
|
{
|
|
m_viewer->goToNextPage();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return isHandled;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimSummaryMultiPlot::handleGlobalWheelEvent( QWheelEvent* wheelEvent )
|
|
{
|
|
if ( m_disableWheelZoom )
|
|
{
|
|
if ( isMouseCursorInsidePlot() )
|
|
{
|
|
if ( wheelEvent->angleDelta().y() > 0 )
|
|
{
|
|
m_viewer->goToPrevPage();
|
|
}
|
|
else if ( wheelEvent->angleDelta().y() < 0 )
|
|
{
|
|
m_viewer->goToNextPage();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::initAfterRead()
|
|
{
|
|
RimMultiPlot::initAfterRead();
|
|
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
plot->axisChanged.connect( this, &RimSummaryMultiPlot::onSubPlotAxisChanged );
|
|
plot->curvesChanged.connect( this, &RimSummaryMultiPlot::onSubPlotChanged );
|
|
plot->titleChanged.connect( this, &RimSummaryMultiPlot::onSubPlotChanged );
|
|
plot->axisChangedReloadRequired.connect( this, &RimSummaryMultiPlot::onSubPlotAxisReloadRequired );
|
|
plot->autoTitleChanged.connect( this, &RimSummaryMultiPlot::onSubPlotAutoTitleChanged );
|
|
}
|
|
updateStepDimensionFromDefault();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::onLoadDataAndUpdate()
|
|
{
|
|
RimMultiPlot::onLoadDataAndUpdate();
|
|
updatePlotTitles();
|
|
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
p->updateAxes();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::zoomAll()
|
|
{
|
|
setAutoValueStates();
|
|
|
|
// Reset zoom to make sure the complete range for min/max is available
|
|
RimMultiPlot::zoomAll();
|
|
|
|
syncAxisRanges();
|
|
|
|
updateTimeAxisRangesFromFirstTimePlot();
|
|
|
|
if ( m_linkSubPlotAxes() )
|
|
{
|
|
// Disable auto scaling for Y axis, use the axis values from the first plot
|
|
setAutoScaleYEnabled( false );
|
|
|
|
if ( !summaryPlots().empty() )
|
|
{
|
|
onSubPlotAxisChanged( nullptr, summaryPlots().front() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateTimeAxisRangesFromFirstTimePlot()
|
|
{
|
|
if ( m_linkTimeAxis )
|
|
{
|
|
auto allPlots = summaryPlots();
|
|
for ( auto plot : allPlots )
|
|
{
|
|
auto curves = plot->summaryAndEnsembleCurves();
|
|
for ( auto curve : curves )
|
|
{
|
|
if ( curve->axisTypeX() == RiaDefines::HorizontalAxisType::TIME )
|
|
{
|
|
setAutoScaleXEnabled( false );
|
|
syncTimeAxisRanges( plot );
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setDefaultRangeAggregationSteppingDimension()
|
|
{
|
|
RiaSummaryAddressAnalyzer analyzer;
|
|
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
auto addresses = RiaSummaryAddressModifier::allSummaryAddressesY( p );
|
|
analyzer.appendAddresses( addresses );
|
|
}
|
|
|
|
auto stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::VECTOR;
|
|
if ( analyzer.regionNumbers().size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::REGION;
|
|
}
|
|
else if ( analyzer.groupNames().size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::GROUP;
|
|
}
|
|
else if ( analyzer.wellNames().size() == 1 )
|
|
{
|
|
auto wellName = *( analyzer.wellNames().begin() );
|
|
|
|
if ( analyzer.wellSegmentNumbers( wellName ).size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::WELL_SEGMENT;
|
|
}
|
|
else if ( analyzer.wellCompletionNumbers( wellName ).size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::WELL_COMPLETION_NUMBER;
|
|
}
|
|
else if ( analyzer.wellConnections( wellName ).size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::WELL_CONNECTION;
|
|
}
|
|
else
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::WELL;
|
|
}
|
|
}
|
|
else if ( analyzer.networkNames().size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::NETWORK;
|
|
}
|
|
else if ( analyzer.aquifers().size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::AQUIFER;
|
|
}
|
|
else if ( analyzer.blocks().size() == 1 )
|
|
{
|
|
stepDimension = RimSummaryDataSourceStepping::SourceSteppingDimension::BLOCK;
|
|
}
|
|
|
|
m_sourceStepping->setStepDimension( stepDimension );
|
|
|
|
// Previously, when the stepping dimension was set to 'well' for range aggregation, it was based on all wells. If one of the wells
|
|
// had extreme values and was not visible, it would set the y-range to match the extreme value, making some curves invisible. We
|
|
// have now changed the default setting to use visible subplots to determine the y-range aggregation.
|
|
// https://github.com/OPM/ResInsight/issues/10543
|
|
|
|
m_axisRangeAggregation = AxisRangeAggregation::NONE;
|
|
|
|
setAutoValueStates();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::syncAxisRanges()
|
|
{
|
|
if ( m_axisRangeAggregation() == AxisRangeAggregation::NONE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Reset zoom for axes with no custom range set to make sure the complete range for min/max is available
|
|
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
for ( auto ax : p->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
ax->setAutoZoomIfNoCustomRangeIsSet();
|
|
}
|
|
}
|
|
updateZoom();
|
|
|
|
if ( m_axisRangeAggregation() == AxisRangeAggregation::SUB_PLOTS )
|
|
{
|
|
std::map<QString, std::pair<double, double>> axisRanges;
|
|
|
|
// gather current min/max values for each category (axis label)
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
double minVal = axis->visibleRangeMin();
|
|
double maxVal = axis->visibleRangeMax();
|
|
if ( axis->isAxisInverted() ) std::swap( minVal, maxVal );
|
|
|
|
auto key = axis->objectName();
|
|
if ( axisRanges.count( key ) == 0 )
|
|
{
|
|
axisRanges[key] = std::make_pair( minVal, maxVal );
|
|
}
|
|
else
|
|
{
|
|
auto& [currentMin, currentMax] = axisRanges[key];
|
|
axisRanges[key] = std::make_pair( std::min( currentMin, minVal ), std::max( currentMax, maxVal ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// set all plots to use the global min/max values for each category
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
auto [minVal, maxVal] = axisRanges[axis->objectName()];
|
|
if ( axis->isAxisInverted() ) std::swap( minVal, maxVal );
|
|
axis->setAutoZoom( false );
|
|
|
|
axis->setAutoValueVisibleRangeMin( minVal );
|
|
axis->setAutoValueVisibleRangeMax( maxVal );
|
|
}
|
|
|
|
plot->updateAxes();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
computeAggregatedAxisRange();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::syncTimeAxisRanges( RimSummaryPlot* sourceSummaryPlot )
|
|
{
|
|
if ( sourceSummaryPlot && m_linkTimeAxis() )
|
|
{
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
if ( plot != sourceSummaryPlot )
|
|
{
|
|
plot->copyAxisPropertiesFromOther( RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM, *sourceSummaryPlot );
|
|
plot->updateAll();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::computeAggregatedAxisRange()
|
|
{
|
|
auto readValues = []( RimSummaryCase* summaryCase, RifEclipseSummaryAddress addr )
|
|
{
|
|
if ( summaryCase && summaryCase->summaryReader() )
|
|
{
|
|
RifSummaryReaderInterface* reader = summaryCase->summaryReader();
|
|
auto [isOk, values] = reader->values( addr );
|
|
return values;
|
|
}
|
|
|
|
return std::vector<double>();
|
|
};
|
|
|
|
auto findMinMaxForSummaryCase = [readValues]( RimSummaryCase* summaryCase, RifEclipseSummaryAddress addr, bool onlyPositiveValues )
|
|
{
|
|
auto values = readValues( summaryCase, addr );
|
|
if ( onlyPositiveValues )
|
|
{
|
|
std::vector<double> positiveValues;
|
|
|
|
for ( const auto& v : values )
|
|
{
|
|
if ( v > 0.0 ) positiveValues.push_back( v );
|
|
}
|
|
|
|
values = positiveValues;
|
|
}
|
|
if ( values.empty() ) return std::make_pair( HUGE_VAL, -HUGE_VAL );
|
|
|
|
auto minMaxPair = std::minmax_element( values.begin(), values.end() );
|
|
double caseMinimum = *minMaxPair.first;
|
|
double caseMaximum = *minMaxPair.second;
|
|
|
|
return std::make_pair( caseMinimum, caseMaximum );
|
|
};
|
|
|
|
auto summaryCasesForCurve = []( RimSummaryCurve* curve, AxisRangeAggregation axisRangeAggregation )
|
|
{
|
|
std::vector<RimSummaryCase*> summaryCases;
|
|
|
|
if ( axisRangeAggregation == AxisRangeAggregation::REALIZATIONS )
|
|
{
|
|
if ( curve->summaryCaseY() )
|
|
{
|
|
auto ensemble = curve->summaryCaseY()->ensemble();
|
|
if ( ensemble )
|
|
{
|
|
summaryCases = ensemble->allSummaryCases();
|
|
}
|
|
else
|
|
{
|
|
summaryCases.push_back( curve->summaryCaseY() );
|
|
}
|
|
}
|
|
}
|
|
else if ( axisRangeAggregation == AxisRangeAggregation::WELLS || axisRangeAggregation == AxisRangeAggregation::REGIONS )
|
|
{
|
|
// Use only the current summary case when aggregation across wells/regions
|
|
summaryCases.push_back( curve->summaryCaseY() );
|
|
}
|
|
|
|
return summaryCases;
|
|
};
|
|
|
|
auto addressesForCurve = []( RimSummaryCurve* curve, AxisRangeAggregation axisRangeAggregation )
|
|
{
|
|
std::vector<RifEclipseSummaryAddress> addresses;
|
|
|
|
auto addr = curve->summaryAddressY();
|
|
if ( axisRangeAggregation == AxisRangeAggregation::REALIZATIONS )
|
|
{
|
|
addresses = { RifEclipseSummaryAddress::fieldAddress( addr.vectorName(), addr.id() ) };
|
|
}
|
|
else if ( axisRangeAggregation == AxisRangeAggregation::WELLS || axisRangeAggregation == AxisRangeAggregation::REGIONS )
|
|
{
|
|
RiaSummaryAddressAnalyzer fallbackAnalyzer;
|
|
RiaSummaryAddressAnalyzer* analyzer = nullptr;
|
|
|
|
if ( curve->summaryCaseY() )
|
|
{
|
|
auto ensemble = curve->summaryCaseY()->ensemble();
|
|
if ( ensemble )
|
|
{
|
|
analyzer = ensemble->addressAnalyzer();
|
|
}
|
|
else
|
|
{
|
|
if ( auto reader = curve->summaryCaseY()->summaryReader() )
|
|
{
|
|
fallbackAnalyzer.appendAddresses( reader->allResultAddresses() );
|
|
}
|
|
analyzer = &fallbackAnalyzer;
|
|
}
|
|
}
|
|
|
|
if ( analyzer )
|
|
{
|
|
if ( axisRangeAggregation == AxisRangeAggregation::WELLS )
|
|
{
|
|
for ( const auto& wellName : analyzer->wellNames() )
|
|
{
|
|
addresses.push_back( RifEclipseSummaryAddress::wellAddress( addr.vectorName(), wellName, addr.id() ) );
|
|
}
|
|
}
|
|
|
|
if ( axisRangeAggregation == AxisRangeAggregation::REGIONS )
|
|
{
|
|
for ( auto regionNumber : analyzer->regionNumbers() )
|
|
{
|
|
addresses.push_back( RifEclipseSummaryAddress::regionAddress( addr.vectorName(), regionNumber, addr.id() ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return addresses;
|
|
};
|
|
|
|
auto findMinMaxForAddressesInSummaryCases = [findMinMaxForSummaryCase]( const std::vector<RifEclipseSummaryAddress>& addresses,
|
|
const std::vector<RimSummaryCase*>& summaryCases,
|
|
bool onlyPositiveValues )
|
|
{
|
|
double minimum = HUGE_VAL;
|
|
double maximum = -HUGE_VAL;
|
|
for ( auto summaryCase : summaryCases )
|
|
{
|
|
for ( const auto& addr : addresses )
|
|
{
|
|
auto [caseMinimum, caseMaximum] = findMinMaxForSummaryCase( summaryCase, addr, onlyPositiveValues );
|
|
minimum = std::min( minimum, caseMinimum );
|
|
maximum = std::max( maximum, caseMaximum );
|
|
}
|
|
}
|
|
|
|
return std::make_pair( minimum, maximum );
|
|
};
|
|
|
|
// gather current min/max values for each category (axis label)
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
std::map<RiuPlotAxis, std::pair<double, double>> axisRanges;
|
|
|
|
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
for ( auto curve : plot->summaryCurves() )
|
|
{
|
|
if ( curve->axisY() == axis->plotAxis() )
|
|
{
|
|
std::vector<RimSummaryCase*> summaryCases = summaryCasesForCurve( curve, m_axisRangeAggregation() );
|
|
std::vector<RifEclipseSummaryAddress> addresses = addressesForCurve( curve, m_axisRangeAggregation() );
|
|
|
|
bool onlyPositiveValues = axis->isLogarithmicScaleEnabled();
|
|
|
|
auto [minimum, maximum] = findMinMaxForAddressesInSummaryCases( addresses, summaryCases, onlyPositiveValues );
|
|
|
|
if ( axisRanges.count( axis->plotAxis() ) == 0 )
|
|
{
|
|
axisRanges[axis->plotAxis()] = std::make_pair( minimum, maximum );
|
|
}
|
|
else
|
|
{
|
|
auto& [currentMin, currentMax] = axisRanges[axis->plotAxis()];
|
|
axisRanges[axis->plotAxis()] = std::make_pair( std::min( currentMin, minimum ), std::max( currentMax, maximum ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( auto curveSet : plot->curveSets() )
|
|
{
|
|
if ( !curveSet->summaryEnsemble() ) continue;
|
|
|
|
if ( curveSet->axisY() == axis->plotAxis() )
|
|
{
|
|
double minimum( std::numeric_limits<double>::infinity() );
|
|
double maximum( -std::numeric_limits<double>::infinity() );
|
|
|
|
auto curves = curveSet->curves();
|
|
if ( !curves.empty() )
|
|
{
|
|
// TODO: Use analyzer as input to addressesForCurve instead of curve
|
|
|
|
auto curve = curves.front();
|
|
|
|
std::vector<RifEclipseSummaryAddress> addresses = addressesForCurve( curve, m_axisRangeAggregation() );
|
|
|
|
for ( const auto& adr : addresses )
|
|
{
|
|
auto [min, max] = curveSet->summaryEnsemble()->minMax( adr );
|
|
|
|
minimum = std::min( min, minimum );
|
|
maximum = std::max( max, maximum );
|
|
}
|
|
}
|
|
|
|
if ( axisRanges.count( axis->plotAxis() ) == 0 )
|
|
{
|
|
axisRanges[axis->plotAxis()] = std::make_pair( minimum, maximum );
|
|
}
|
|
else
|
|
{
|
|
auto& [currentMin, currentMax] = axisRanges[axis->plotAxis()];
|
|
axisRanges[axis->plotAxis()] = std::make_pair( std::min( currentMin, minimum ), std::max( currentMax, maximum ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// set all plots to use the global min/max values for each category
|
|
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
auto [minVal, maxVal] = axisRanges[axis->plotAxis()];
|
|
if ( RiaDefines::isVertical( axis->plotAxis().axis() ) && !std::isinf( minVal ) && !std::isinf( maxVal ) )
|
|
{
|
|
axis->setAutoZoom( false );
|
|
|
|
if ( axis->isAxisInverted() ) std::swap( minVal, maxVal );
|
|
|
|
auto [adjustedMinVal, adjustedMaxVal] = adjustedMinMax( axis, minVal, maxVal );
|
|
|
|
axis->setAutoValueVisibleRangeMin( adjustedMinVal );
|
|
axis->setAutoValueVisibleRangeMax( adjustedMaxVal );
|
|
}
|
|
}
|
|
|
|
plot->updateAxes();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updatePlotVisibility()
|
|
{
|
|
auto hasValuesAboveLimit = []( RimSummaryPlot* plot, double limit )
|
|
{
|
|
for ( auto curve : plot->summaryAndEnsembleCurves() )
|
|
{
|
|
auto values = curve->valuesY();
|
|
if ( values.empty() ) continue;
|
|
|
|
auto maxValue = std::max_element( values.begin(), values.end() );
|
|
if ( maxValue != values.end() && ( *maxValue > limit ) ) return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
bool hasValueAboveLimit = hasValuesAboveLimit( plot, m_plotFilterYAxisThreshold );
|
|
plot->setShowWindow( hasValueAboveLimit );
|
|
}
|
|
|
|
updateLayout();
|
|
updateConnectedEditors();
|
|
|
|
if ( !m_viewer.isNull() ) m_viewer->scheduleUpdate();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setAutoValueStates()
|
|
{
|
|
bool enableMinMaxAutoValue = m_axisRangeAggregation() != AxisRangeAggregation::NONE;
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
setAutoValueStatesForPlot( p, enableMinMaxAutoValue, m_autoAdjustAppearance() );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setAutoValueStatesForPlot( RimSummaryPlot* summaryPlot, bool enableAutoValueMinMax, bool enableAutoValueAppearance )
|
|
{
|
|
auto timeAxisProp = summaryPlot->timeAxisProperties();
|
|
if ( timeAxisProp ) timeAxisProp->enableAutoValueForMajorTickmarkCount( enableAutoValueAppearance );
|
|
|
|
for ( auto plotAxis : summaryPlot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
plotAxis->enableAutoValueMinMax( enableAutoValueMinMax );
|
|
plotAxis->enableAutoValueForMajorTickmarkCount( enableAutoValueAppearance );
|
|
plotAxis->enableAutoValueForScaleFactor( enableAutoValueAppearance );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::summaryPlotItemInfos( QList<caf::PdmOptionItemInfo>* optionInfos ) const
|
|
{
|
|
for ( RimSummaryPlot* plot : summaryPlots() )
|
|
{
|
|
QString displayName;
|
|
|
|
if ( plot && plot->userDescriptionField() && plot->userDescriptionField() )
|
|
{
|
|
displayName = plot->userDescriptionField()->uiCapability()->uiValue().toString();
|
|
}
|
|
|
|
optionInfos->push_back( caf::PdmOptionItemInfo( displayName, plot, false, plot->uiCapability()->uiIconProvider() ) );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::analyzePlotsAndAdjustAppearanceSettings()
|
|
{
|
|
if ( m_autoAdjustAppearance )
|
|
{
|
|
if ( !m_linkSubPlotAxes )
|
|
{
|
|
// Required to sync axis ranges before computing the auto scale
|
|
syncAxisRanges();
|
|
}
|
|
|
|
RiaSummaryAddressAnalyzer analyzer;
|
|
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
auto addresses = RiaSummaryAddressModifier::allSummaryAddressesY( p );
|
|
analyzer.appendAddresses( addresses );
|
|
}
|
|
|
|
bool canShowOneAxisTitlePerRow = analyzer.isSingleQuantityIgnoreHistory() && ( m_axisRangeAggregation() != AxisRangeAggregation::NONE );
|
|
|
|
const bool notifyFieldChanged = false;
|
|
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
if ( auto timeAxisProp = p->timeAxisProperties() )
|
|
{
|
|
auto tickMarkCount = ( columnCount() < 3 ) ? RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_DEFAULT
|
|
: RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_FEW;
|
|
|
|
timeAxisProp->setAutoValueForMajorTickmarkCount( tickMarkCount, notifyFieldChanged );
|
|
}
|
|
|
|
for ( auto* axisProp : p->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
auto tickMarkCount = ( rowsPerPage() == 1 ) ? RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_DEFAULT
|
|
: RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_FEW;
|
|
|
|
axisProp->setAutoValueForMajorTickmarkCount( tickMarkCount, notifyFieldChanged );
|
|
|
|
axisProp->computeAndSetAutoValueForScaleFactor();
|
|
|
|
if ( canShowOneAxisTitlePerRow )
|
|
{
|
|
auto [row, col] = gridLayoutInfoForSubPlot( p );
|
|
|
|
bool isFirstColumn = ( col == 0 );
|
|
axisProp->setShowUnitText( isFirstColumn );
|
|
axisProp->setShowDescription( isFirstColumn );
|
|
}
|
|
else
|
|
{
|
|
axisProp->setShowUnitText( true );
|
|
axisProp->setShowDescription( true );
|
|
}
|
|
}
|
|
|
|
p->updateAxes();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( auto p : summaryPlots() )
|
|
{
|
|
for ( auto* axisProp : p->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
|
|
{
|
|
axisProp->computeAndSetAutoValueForScaleFactor();
|
|
axisProp->setShowUnitText( true );
|
|
axisProp->setShowDescription( true );
|
|
}
|
|
|
|
p->updateAxes();
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::makeSureIsVisible( RimSummaryPlot* summaryPlot )
|
|
{
|
|
if ( summaryPlot->plotWidget() && !m_viewer.isNull() ) m_viewer->scrollToPlot( summaryPlot->plotWidget() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setSubPlotAxesLinked( bool enable )
|
|
{
|
|
m_linkSubPlotAxes = enable;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimSummaryMultiPlot::isSubPlotAxesLinked() const
|
|
{
|
|
return m_linkSubPlotAxes();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::setTimeAxisLinked( bool enable )
|
|
{
|
|
m_linkTimeAxis = enable;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimSummaryMultiPlot::isTimeAxisLinked() const
|
|
{
|
|
return m_linkTimeAxis();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::pair<int, int> RimSummaryMultiPlot::gridLayoutInfoForSubPlot( RimSummaryPlot* summaryPlot ) const
|
|
{
|
|
auto it = m_gridLayoutInfo.find( summaryPlot );
|
|
if ( it != m_gridLayoutInfo.end() ) return it->second;
|
|
|
|
return { -1, -1 };
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::onSubPlotChanged( const caf::SignalEmitter* emitter )
|
|
{
|
|
updatePlotTitles();
|
|
applyPlotWindowTitleToWidgets();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::onSubPlotAxisChanged( const caf::SignalEmitter* emitter, RimSummaryPlot* summaryPlot )
|
|
{
|
|
syncTimeAxisRanges( summaryPlot );
|
|
|
|
if ( m_linkSubPlotAxes() )
|
|
{
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
if ( plot != summaryPlot )
|
|
{
|
|
plot->copyMatchingAxisPropertiesFromOther( *summaryPlot );
|
|
plot->updateAll();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
syncAxisRanges();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::onSubPlotAxisReloadRequired( const caf::SignalEmitter* emitter, RimSummaryPlot* summaryPlot )
|
|
{
|
|
if ( !summaryPlot ) return;
|
|
|
|
if ( m_linkTimeAxis() )
|
|
{
|
|
syncTimeAxisRanges( summaryPlot );
|
|
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
plot->loadDataAndUpdate();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
summaryPlot->loadDataAndUpdate();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::onSubPlotAutoTitleChanged( const caf::SignalEmitter* emitter, bool isEnabled )
|
|
{
|
|
m_autoSubPlotTitle = isEnabled;
|
|
|
|
loadDataAndUpdate();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateReadOnlyState()
|
|
{
|
|
m_axisRangeAggregation.uiCapability()->setUiReadOnly( m_linkSubPlotAxes() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateReadOutSettings()
|
|
{
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
if ( !activeReadoutSettings()->enableVerticalLine() )
|
|
{
|
|
if ( auto axisProps = plot->timeAxisProperties() )
|
|
{
|
|
axisProps->removeAllAnnotations();
|
|
}
|
|
}
|
|
|
|
if ( !activeReadoutSettings()->enableHorizontalLine() )
|
|
{
|
|
if ( auto axis = plot->axisPropertiesForPlotAxis( RiuPlotAxis::defaultLeft() ) )
|
|
{
|
|
axis->removeAllAnnotations();
|
|
}
|
|
}
|
|
|
|
plot->enableCurvePointTracking( activeReadoutSettings()->enableCurvePointTracking() );
|
|
|
|
plot->updateAndRedrawTimeAnnotations();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::pair<double, double> RimSummaryMultiPlot::adjustedMinMax( const RimPlotAxisProperties* axis, double min, double max ) const
|
|
{
|
|
if ( !axis->isLogarithmicScaleEnabled() )
|
|
{
|
|
int maxMajorTickIntervalCount = RimPlotAxisProperties::tickmarkCountFromEnum( axis->majorTickmarkCount() );
|
|
double stepSize = 0.0;
|
|
QwtLinearScaleEngine scaleEngine;
|
|
|
|
// Do not adjust minimum value, as we usually want to keep zero unchanged
|
|
double adjustedMin = min;
|
|
|
|
// Adjust the max value to get some space between the top of the plot and the top of the curve
|
|
double adjustedMax = max * 1.05;
|
|
|
|
scaleEngine.autoScale( maxMajorTickIntervalCount, adjustedMin, adjustedMax, stepSize );
|
|
|
|
return { adjustedMin, adjustedMax };
|
|
}
|
|
|
|
auto adjustedMin = RiaNumericalTools::roundToClosestPowerOfTenFloor( min );
|
|
auto adjustedMax = RiaNumericalTools::roundToClosestPowerOfTenCeil( max );
|
|
|
|
return { adjustedMin, adjustedMax };
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSummaryPlotReadOut* RimSummaryMultiPlot::activeReadoutSettings() const
|
|
{
|
|
if ( auto plotCollection = RimMainPlotCollection::current()->summaryMultiPlotCollection() )
|
|
{
|
|
if ( plotCollection->commonReadOutSettings().has_value() )
|
|
{
|
|
return plotCollection->commonReadOutSettings().value();
|
|
}
|
|
}
|
|
|
|
return m_readOutSettings();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QWidget* RimSummaryMultiPlot::createViewWidget( QWidget* mainWindowParent )
|
|
{
|
|
if ( m_viewer.isNull() )
|
|
{
|
|
m_viewer = new RiuSummaryMultiPlotBook( this, mainWindowParent );
|
|
}
|
|
recreatePlotWidgets();
|
|
|
|
updateReadOutSettings();
|
|
|
|
return m_viewer;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::onPlotAdditionOrRemoval()
|
|
{
|
|
m_disableWheelZoom = ( summaryPlots().size() > 1 );
|
|
|
|
RimMultiPlot::onPlotAdditionOrRemoval();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Gather what every plot in the window is about to read and hand it to each ensemble as one set. A plot
|
|
/// prefetches for itself as well, but the plots are loaded one at a time, so doing it here is what lets a
|
|
/// remote source load the whole window in one request group rather than one per plot.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::prefetchPlotData()
|
|
{
|
|
std::map<RimSummaryEnsemble*, std::vector<RifEclipseSummaryAddress>> addressesByEnsemble;
|
|
|
|
for ( RimSummaryPlot* plot : summaryPlots() )
|
|
{
|
|
if ( !plot ) continue;
|
|
|
|
for ( const auto& [ensemble, addresses] : plot->summaryAddressesByEnsemble() )
|
|
{
|
|
auto& allAddresses = addressesByEnsemble[ensemble];
|
|
allAddresses.insert( allAddresses.end(), addresses.begin(), addresses.end() );
|
|
}
|
|
}
|
|
|
|
for ( const auto& [ensemble, addresses] : addressesByEnsemble )
|
|
{
|
|
ensemble->prefetchSummaryData( addresses );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimSummaryMultiPlot::isStepDimensionSharedAmongSubPlots()
|
|
{
|
|
using Dim = RimSummaryDataSourceStepping::SourceSteppingDimension;
|
|
|
|
populateNameHelper( m_nameHelper.get() );
|
|
|
|
switch ( m_sourceStepping->stepDimension() )
|
|
{
|
|
case Dim::SUMMARY_CASE:
|
|
case Dim::ENSEMBLE:
|
|
return m_nameHelper->isCaseInTitle();
|
|
case Dim::WELL:
|
|
return m_nameHelper->isWellNameInTitle();
|
|
case Dim::GROUP:
|
|
return m_nameHelper->isGroupNameInTitle();
|
|
case Dim::NETWORK:
|
|
return m_nameHelper->isNetworkInTitle();
|
|
case Dim::REGION:
|
|
return m_nameHelper->isRegionInTitle();
|
|
case Dim::VECTOR:
|
|
return !m_nameHelper->titleVectorName().empty();
|
|
case Dim::BLOCK:
|
|
return m_nameHelper->isBlockInTitle();
|
|
case Dim::WELL_SEGMENT:
|
|
return m_nameHelper->isSegmentInTitle();
|
|
case Dim::WELL_CONNECTION:
|
|
return m_nameHelper->isConnectionInTitle();
|
|
case Dim::WELL_COMPLETION_NUMBER:
|
|
return m_nameHelper->isWellCompletionInTitle();
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
caf::PdmObject* RimSummaryMultiPlot::steppingSourceObject()
|
|
{
|
|
if ( !isStepDimensionSharedAmongSubPlots() )
|
|
{
|
|
auto* selectedPlot = caf::SelectionManager::instance()->selectedItemOfType<RimSummaryPlot>();
|
|
if ( selectedPlot && selectedPlot->firstAncestorOrThisOfType<RimSummaryMultiPlot>() == this ) return selectedPlot;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::appendSubPlotByStepping( int direction )
|
|
{
|
|
m_sourceStepping->setSourceSteppingObject( steppingSourceObject() );
|
|
|
|
auto applySteppingToPlots = []( const std::vector<RimSummaryPlot*>& summaryPlots, RimSummaryPlotSourceStepping* sourceStepper, int direction )
|
|
{
|
|
if ( !sourceStepper ) return;
|
|
|
|
for ( auto newPlot : summaryPlots )
|
|
{
|
|
if ( sourceStepper->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::SUMMARY_CASE )
|
|
{
|
|
RimSummaryCase* newCase = sourceStepper->stepCase( direction );
|
|
for ( auto curve : newPlot->allCurves() )
|
|
{
|
|
curve->setSummaryCaseY( newCase );
|
|
|
|
// NOTE: If summary cross plots should be handled here, we also need to call
|
|
// curve->setSummaryCaseX( newCase );
|
|
// Setting summaryCaseX with a default uninitialized summary address causes issues for the summary
|
|
// name analyzer
|
|
}
|
|
}
|
|
else if ( sourceStepper->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::ENSEMBLE )
|
|
{
|
|
RimSummaryEnsemble* newEnsemble = sourceStepper->stepEnsemble( direction );
|
|
for ( auto curveSet : newPlot->curveSets() )
|
|
{
|
|
curveSet->setSummaryEnsemble( newEnsemble );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<RiaSummaryCurveAddress> newCurveAdrs;
|
|
|
|
auto curveAddressProviders = RiaSummaryAddressModifier::createAddressProviders( newPlot );
|
|
for ( const auto& adr : RiaSummaryAddressModifier::curveAddresses( curveAddressProviders ) )
|
|
{
|
|
const auto adrX = sourceStepper->stepAddress( adr.summaryAddressX(), direction );
|
|
const auto adrY = sourceStepper->stepAddress( adr.summaryAddressY(), direction );
|
|
newCurveAdrs.push_back( RiaSummaryCurveAddress( adrX, adrY ) );
|
|
}
|
|
|
|
RiaSummaryAddressModifier::applyAddressesToCurveAddressProviders( curveAddressProviders, newCurveAdrs );
|
|
}
|
|
}
|
|
};
|
|
|
|
if ( m_sourceStepping()->isAtEnd( direction ) ) return;
|
|
|
|
if ( caf::SelectionManager::instance()->selectedItemOfType<RimSummaryMultiPlot>() != nullptr )
|
|
{
|
|
if ( auto plotCollection = RimMainPlotCollection::current()->summaryMultiPlotCollection() )
|
|
{
|
|
auto copy = plotCollection->duplicatePlot( this );
|
|
|
|
applySteppingToPlots( copy->summaryPlots(), m_sourceStepping(), direction );
|
|
|
|
copy->loadDataAndUpdate();
|
|
copy->updateConnectedEditors();
|
|
copy->updateSourceStepper();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<RimPlot*> plots = m_sourceStepping->plotsMatchingStepSettings( summaryPlots() );
|
|
if ( !plots.empty() )
|
|
{
|
|
std::vector<RimSummaryPlot*> summaryPlots;
|
|
auto newPlots = RiaSummaryPlotTools::duplicatePlots( plots );
|
|
for ( auto plot : newPlots )
|
|
{
|
|
if ( RimSummaryPlot* newPlot = dynamic_cast<RimSummaryPlot*>( plot ) )
|
|
{
|
|
addPlot( newPlot );
|
|
newPlot->resolveReferencesRecursively();
|
|
summaryPlots.push_back( newPlot );
|
|
}
|
|
}
|
|
applySteppingToPlots( summaryPlots, m_sourceStepping(), direction );
|
|
}
|
|
|
|
loadDataAndUpdate();
|
|
updateConnectedEditors();
|
|
|
|
RiuPlotMainWindowTools::selectAsCurrentItem( summaryPlots().back() );
|
|
|
|
updateSourceStepper();
|
|
}
|
|
|
|
RiuPlotMainWindowTools::refreshToolbars();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::appendCurveByStepping( int direction )
|
|
{
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
std::vector<caf::PdmObjectHandle*> addresses;
|
|
|
|
for ( auto curve : plot->allCurves() )
|
|
{
|
|
auto address = curve->summaryAddressY();
|
|
auto sumCase = curve->summaryCaseY();
|
|
int sumCaseId = sumCase->caseId();
|
|
if ( m_sourceStepping()->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::SUMMARY_CASE )
|
|
{
|
|
auto nextSumCase = m_sourceStepping->stepCase( direction );
|
|
if ( nextSumCase ) sumCaseId = nextSumCase->caseId();
|
|
}
|
|
else
|
|
{
|
|
address = m_sourceStepping->stepAddress( address, direction );
|
|
}
|
|
addresses.push_back( RimSummaryAddress::wrapFileReaderAddress( address, sumCaseId ) );
|
|
}
|
|
|
|
for ( auto curveSet : plot->curveSets() )
|
|
{
|
|
auto address = curveSet->summaryAddressY();
|
|
auto sumEns = curveSet->summaryEnsemble();
|
|
int sumEnsId = sumEns->ensembleId();
|
|
if ( m_sourceStepping()->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::ENSEMBLE )
|
|
{
|
|
auto nextEns = m_sourceStepping->stepEnsemble( direction );
|
|
if ( nextEns ) sumEnsId = nextEns->ensembleId();
|
|
}
|
|
else
|
|
{
|
|
address = m_sourceStepping->stepAddress( address, direction );
|
|
}
|
|
addresses.push_back( RimSummaryAddress::wrapFileReaderAddress( address, -1, sumEnsId ) );
|
|
}
|
|
|
|
plot->handleDroppedObjects( addresses );
|
|
|
|
for ( auto adr : addresses )
|
|
{
|
|
delete adr;
|
|
}
|
|
}
|
|
|
|
m_sourceStepping->updateStepIndex( direction );
|
|
|
|
RiuPlotMainWindowTools::refreshToolbars();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateSourceStepper()
|
|
{
|
|
if ( summaryPlots().empty() ) return;
|
|
|
|
RimSummaryPlot* plot = summaryPlots().back();
|
|
|
|
auto sourceStepper = plot->sourceStepper();
|
|
if ( sourceStepper == nullptr ) return;
|
|
|
|
m_sourceStepping->syncWithStepper( sourceStepper );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::keepVisiblePageAfterUpdate( bool keepPage )
|
|
{
|
|
if ( !m_viewer ) return;
|
|
|
|
if ( keepPage ) m_viewer->keepCurrentPageAfterUpdate();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::storeStepDimensionFromToolbar()
|
|
{
|
|
m_defaultStepDimension = m_sourceStepping->stepDimension();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateStepDimensionFromDefault()
|
|
{
|
|
m_sourceStepping->setStepDimension( m_defaultStepDimension() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::selectWell( QString wellName )
|
|
{
|
|
if ( !m_allow3DSelectionLink ) return;
|
|
if ( m_sourceStepping->stepDimension() != SourceSteppingDimension::WELL ) return;
|
|
m_sourceStepping->setStep( wellName );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimSummaryMultiPlot::updateReadOutLines( double qwtTimeValue, double yValue )
|
|
{
|
|
auto readOutSettings = activeReadoutSettings();
|
|
if ( !readOutSettings ) return;
|
|
|
|
if ( !readOutSettings->enableVerticalLine() && !readOutSettings->enableHorizontalLine() ) return;
|
|
|
|
const auto timeTValue = RiaTimeTTools::fromDouble( qwtTimeValue );
|
|
const QString dateFormatString = RiaQDateTimeTools::dateFormatString( RiaPreferences::current()->dateFormat(),
|
|
RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY );
|
|
|
|
for ( auto plot : summaryPlots() )
|
|
{
|
|
if ( !plot ) continue;
|
|
|
|
if ( readOutSettings->enableVerticalLine() && plot->timeAxisProperties() )
|
|
{
|
|
plot->timeAxisProperties()->removeAllAnnotations();
|
|
|
|
auto lineAppearance = readOutSettings->lineAppearance();
|
|
auto anno = RimTimeAxisAnnotation::createTimeAnnotation( timeTValue, lineAppearance->color() );
|
|
|
|
Qt::PenStyle style = lineAppearance->isDashed() ? Qt::PenStyle::DashLine : Qt::PenStyle::SolidLine;
|
|
anno->setPenStyle( style );
|
|
anno->setAlignment( readOutSettings->verticalLineLabelAlignment() );
|
|
|
|
plot->timeAxisProperties()->appendAnnotation( anno );
|
|
}
|
|
|
|
if ( readOutSettings->enableHorizontalLine() )
|
|
{
|
|
std::vector<RimSummaryCurve*> summaryCurves;
|
|
|
|
// 1. Check if any curves are highlighted
|
|
if ( auto plotWidget = dynamic_cast<RiuQwtPlotWidget*>( plot->plotWidget() ) )
|
|
{
|
|
for ( auto highlightCurve : plotWidget->highlightedCurves() )
|
|
{
|
|
if ( highlightCurve.isNull() ) continue;
|
|
|
|
if ( auto summaryCurve = dynamic_cast<RimSummaryCurve*>( highlightCurve.p() ) )
|
|
{
|
|
summaryCurves.push_back( summaryCurve );
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. If no curves are highlighted, use summary curves from single realizations
|
|
if ( summaryCurves.empty() )
|
|
{
|
|
summaryCurves = plot->summaryCurves();
|
|
}
|
|
|
|
auto annotationAxis = dynamic_cast<RimPlotAxisProperties*>( plot->axisPropertiesForPlotAxis( RiuPlotAxis::defaultLeft() ) );
|
|
if ( !summaryCurves.empty() )
|
|
{
|
|
auto firstCurve = summaryCurves.front();
|
|
yValue = firstCurve->yValueAtTimeT( timeTValue );
|
|
annotationAxis = dynamic_cast<RimPlotAxisProperties*>( plot->axisPropertiesForPlotAxis( firstCurve->axisY() ) );
|
|
}
|
|
|
|
if ( annotationAxis )
|
|
{
|
|
annotationAxis->removeAllAnnotations();
|
|
|
|
auto anno = new RimPlotAxisAnnotation();
|
|
anno->setAnnotationType( RimPlotAxisAnnotation::AnnotationType::LINE );
|
|
|
|
anno->setValue( yValue );
|
|
|
|
auto scaledValue = yValue / annotationAxis->scaleFactor();
|
|
auto valueText = caf::PdmUiNumberFormat::valueToText( scaledValue, caf::NumberFormatType::FIXED, 2 );
|
|
|
|
anno->setName( valueText );
|
|
|
|
auto lineAppearance = readOutSettings->lineAppearance();
|
|
|
|
Qt::PenStyle style = lineAppearance->isDashed() ? Qt::PenStyle::DashLine : Qt::PenStyle::SolidLine;
|
|
anno->setPenStyle( style );
|
|
anno->setColor( lineAppearance->color() );
|
|
anno->setAlignment( readOutSettings->horizontalLineLabelAlignment() );
|
|
|
|
annotationAxis->appendAnnotation( anno );
|
|
}
|
|
}
|
|
|
|
// Calling plot->updateAxes() does not work for the first plot in a multiplot. Use fine grained update of annotation objects.
|
|
plot->updateAnnotationsInPlotWidget();
|
|
plot->updatePlotWidgetFromAxisRanges();
|
|
}
|
|
}
|