mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-24 22:27:55 -05:00
Adds a "Plot 1-SGAS" checkbox to the relative permeability plot panel. When enabled (only available for two-phase gas-water systems), gas curves (KRG, KROG, PCOG/PCGW) are plotted against (1 - SGAS) instead of SGAS, aligning the gas saturation axis with the water saturation axis, matching normal relperm/capillary pressure plotting practice. Share the saturation transform between plotting and Show Plot Data export via a new applyOneMinusSgasTransform() helper, so the exported ascii data matches the rendered curves when the Plot 1-SGAS option is enabled.
1142 lines
46 KiB
C++
1142 lines
46 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2017 Statoil 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 "RiuRelativePermeabilityPlotPanel.h"
|
|
|
|
#include "RiaCurveDataTools.h"
|
|
#include "RiaDefines.h"
|
|
#include "RiaEclipseUnitTools.h"
|
|
#include "RiaInterpolationTools.h"
|
|
#include "RiaPhaseTools.h"
|
|
#include "RiaPlotDefines.h"
|
|
#include "RiaResultNames.h"
|
|
|
|
#include "RigFlowDiagSolverInterface.h"
|
|
|
|
#include "RiuDockedQwtPlot.h"
|
|
#include "RiuGuiTheme.h"
|
|
#include "RiuPlotCurveSymbol.h"
|
|
#include "RiuQwtPlotTools.h"
|
|
#include "RiuQwtSymbol.h"
|
|
#include "RiuRelativePermeabilityPlotUpdater.h"
|
|
#include "RiuTextDialog.h"
|
|
|
|
#include "cafAssert.h"
|
|
|
|
#include "qwt_legend.h"
|
|
#include "qwt_picker_machine.h"
|
|
#include "qwt_plot.h"
|
|
#include "qwt_plot_curve.h"
|
|
#include "qwt_plot_marker.h"
|
|
#include "qwt_plot_picker.h"
|
|
#include "qwt_scale_engine.h"
|
|
#include "qwt_symbol.h"
|
|
#include "qwt_text.h"
|
|
|
|
#include <QButtonGroup>
|
|
#include <QCheckBox>
|
|
#include <QContextMenuEvent>
|
|
#include <QGridLayout>
|
|
#include <QGroupBox>
|
|
#include <QHBoxLayout>
|
|
#include <QMenu>
|
|
#include <QPushButton>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <functional>
|
|
|
|
//==================================================================================================
|
|
//
|
|
//
|
|
//
|
|
//==================================================================================================
|
|
class RelPermQwtPlot : public RiuDockedQwtPlot
|
|
{
|
|
public:
|
|
RelPermQwtPlot( QWidget* parent )
|
|
: RiuDockedQwtPlot( parent )
|
|
{
|
|
}
|
|
QSize sizeHint() const override { return QSize( 100, 100 ); }
|
|
QSize minimumSizeHint() const override { return QSize( 0, 0 ); }
|
|
};
|
|
|
|
//==================================================================================================
|
|
//
|
|
//
|
|
//
|
|
//==================================================================================================
|
|
class RiuRelPermQwtPicker : public QwtPicker
|
|
{
|
|
public:
|
|
RiuRelPermQwtPicker( QwtPlot* plot, std::function<QString()> textProvider )
|
|
: QwtPicker( QwtPicker::NoRubberBand, QwtPicker::AlwaysOn, plot->canvas() )
|
|
, m_textProvider( textProvider )
|
|
{
|
|
setStateMachine( new QwtPickerTrackerMachine );
|
|
}
|
|
|
|
QwtText trackerText( const QPoint& ) const override
|
|
{
|
|
QwtText text( m_textProvider() );
|
|
text.setRenderFlags( Qt::AlignLeft );
|
|
return text;
|
|
}
|
|
|
|
private:
|
|
std::function<QString()> m_textProvider;
|
|
};
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// \class RiuRelativePermeabilityPlotPanel
|
|
///
|
|
///
|
|
///
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel( QWidget* parent )
|
|
: QWidget( parent )
|
|
, m_unitSystem( RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN )
|
|
, m_swat( HUGE_VAL )
|
|
, m_sgas( HUGE_VAL )
|
|
, m_plotUpdater( new RiuRelativePermeabilityPlotUpdater( this ) )
|
|
, m_qwtPlot( nullptr )
|
|
, m_curveSetGroupBox( nullptr )
|
|
, m_showDrainageCheckBox( nullptr )
|
|
, m_showImbibitionCheckBox( nullptr )
|
|
, m_selectedCurvesButtonGroup( nullptr )
|
|
, m_groupBox( nullptr )
|
|
, m_logarithmicScaleKrAxisCheckBox( nullptr )
|
|
, m_showUnscaledCheckBox( nullptr )
|
|
, m_showScaledCheckBox( nullptr )
|
|
, m_fixedXAxisCheckBox( nullptr )
|
|
, m_fixedLeftYAxisCheckBox( nullptr )
|
|
, m_plotOneMinusSgasCheckBox( nullptr )
|
|
, m_trackerPlotMarker( nullptr )
|
|
|
|
{
|
|
m_qwtPlot = new RelPermQwtPlot( this );
|
|
m_qwtPlot->setProperty( "qss-class", "RelPermPlot" );
|
|
|
|
setPlotDefaults( m_qwtPlot );
|
|
applyFontSizes( false );
|
|
|
|
// Initialize picker for curve value tracking
|
|
m_qwtPicker = new RiuRelPermQwtPicker( m_qwtPlot, [this]() { return m_trackerLabel; } );
|
|
RiuGuiTheme::styleQwtItem( m_qwtPicker );
|
|
connect( m_qwtPicker, SIGNAL( activated( bool ) ), this, SLOT( slotPickerActivated( bool ) ) );
|
|
connect( m_qwtPicker, SIGNAL( moved( const QPoint& ) ), this, SLOT( slotPickerPointChanged( const QPoint& ) ) );
|
|
|
|
m_selectedCurvesButtonGroup = new QButtonGroup( this );
|
|
m_selectedCurvesButtonGroup->setExclusive( false );
|
|
|
|
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KRW" ), RigFlowDiagDefines::RelPermCurve::KRW );
|
|
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KRG" ), RigFlowDiagDefines::RelPermCurve::KRG );
|
|
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KROW" ), RigFlowDiagDefines::RelPermCurve::KROW );
|
|
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KROG" ), RigFlowDiagDefines::RelPermCurve::KROG );
|
|
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "PCOW" ), RigFlowDiagDefines::RelPermCurve::PCOW );
|
|
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "PCOG" ), RigFlowDiagDefines::RelPermCurve::PCOG );
|
|
|
|
// Create Curve Set groupbox
|
|
m_curveSetGroupBox = new QGroupBox( "Curve Set" );
|
|
QHBoxLayout* curveSetLayout = new QHBoxLayout;
|
|
m_curveSetGroupBox->setLayout( curveSetLayout );
|
|
|
|
m_showDrainageCheckBox = new QCheckBox( "Drainage" );
|
|
m_showImbibitionCheckBox = new QCheckBox( "Imbibition" );
|
|
m_showDrainageCheckBox->setChecked( true );
|
|
m_showImbibitionCheckBox->setChecked( false );
|
|
|
|
curveSetLayout->addWidget( m_showDrainageCheckBox );
|
|
curveSetLayout->addWidget( m_showImbibitionCheckBox );
|
|
|
|
m_groupBox = new QGroupBox( "Curves" );
|
|
QGridLayout* groupBoxLayout = new QGridLayout;
|
|
m_groupBox->setLayout( groupBoxLayout );
|
|
|
|
QList<QAbstractButton*> checkButtonList = m_selectedCurvesButtonGroup->buttons();
|
|
for ( int i = 0; i < checkButtonList.size(); i++ )
|
|
{
|
|
checkButtonList[i]->setChecked( true );
|
|
groupBoxLayout->addWidget( checkButtonList[i], i / 2, i % 2 );
|
|
}
|
|
|
|
m_logarithmicScaleKrAxisCheckBox = new QCheckBox( "Log Scale Kr Axis" );
|
|
m_showUnscaledCheckBox = new QCheckBox( "Show Unscaled" );
|
|
m_showScaledCheckBox = new QCheckBox( "Show Scaled" );
|
|
m_fixedXAxisCheckBox = new QCheckBox( "Fixed [0, 1] X-axis" );
|
|
m_fixedLeftYAxisCheckBox = new QCheckBox( "Fixed [0, 1] Kr-axis" );
|
|
m_plotOneMinusSgasCheckBox = new QCheckBox( "Plot 1-SGAS" );
|
|
m_plotOneMinusSgasCheckBox->setToolTip(
|
|
"Plot gas curves (and PCGW) as a function of (1 - SGAS), aligning the gas saturation axis with the water saturation axis. "
|
|
"Only available for two-phase gas-water systems." );
|
|
|
|
m_fixedXAxisCheckBox->setChecked( true );
|
|
m_fixedLeftYAxisCheckBox->setChecked( true );
|
|
m_showScaledCheckBox->setChecked( true );
|
|
|
|
QCheckBox* showCurveSelection = new QCheckBox( "Show Curve Selection" );
|
|
showCurveSelection->setCheckState( Qt::Unchecked );
|
|
connect( showCurveSelection, SIGNAL( stateChanged( int ) ), SLOT( slotShowCurveSelectionWidgets( int ) ) );
|
|
|
|
QVBoxLayout* leftLayout = new QVBoxLayout;
|
|
leftLayout->addWidget( m_curveSetGroupBox );
|
|
leftLayout->addWidget( showCurveSelection );
|
|
leftLayout->addWidget( m_groupBox );
|
|
leftLayout->addWidget( m_logarithmicScaleKrAxisCheckBox );
|
|
leftLayout->addWidget( m_showScaledCheckBox );
|
|
leftLayout->addWidget( m_showUnscaledCheckBox );
|
|
leftLayout->addWidget( m_fixedXAxisCheckBox );
|
|
leftLayout->addWidget( m_fixedLeftYAxisCheckBox );
|
|
leftLayout->addWidget( m_plotOneMinusSgasCheckBox );
|
|
leftLayout->addStretch( 1 );
|
|
|
|
QHBoxLayout* mainLayout = new QHBoxLayout();
|
|
mainLayout->addLayout( leftLayout );
|
|
mainLayout->addWidget( m_qwtPlot );
|
|
mainLayout->setContentsMargins( 5, 0, 0, 0 );
|
|
|
|
setLayout( mainLayout );
|
|
|
|
connect( m_selectedCurvesButtonGroup, SIGNAL( idClicked( int ) ), SLOT( slotButtonInButtonGroupClicked( int ) ) );
|
|
connect( m_showDrainageCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_showImbibitionCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_logarithmicScaleKrAxisCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_showUnscaledCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_showScaledCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_fixedXAxisCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_fixedLeftYAxisCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
connect( m_plotOneMinusSgasCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
|
|
|
|
slotShowCurveSelectionWidgets( showCurveSelection->checkState() );
|
|
|
|
plotUiSelectedCurves();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuRelativePermeabilityPlotPanel::~RiuRelativePermeabilityPlotPanel()
|
|
{
|
|
}
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::setPlotDefaults( QwtPlot* plot )
|
|
{
|
|
RiuQwtPlotTools::setCommonPlotBehaviour( plot );
|
|
|
|
{
|
|
QwtText plotTitle = plot->title();
|
|
QFont titleFont = plotTitle.font();
|
|
titleFont.setPointSize( 10 );
|
|
plotTitle.setFont( titleFont );
|
|
plot->setTitle( plotTitle );
|
|
}
|
|
|
|
plot->setAxesCount( QwtAxis::XBottom, 1 );
|
|
plot->setAxesCount( QwtAxis::YLeft, 1 );
|
|
|
|
plot->setAxisMaxMinor( QwtAxis::XBottom, 2 );
|
|
plot->setAxisMaxMinor( QwtAxis::YLeft, 3 );
|
|
|
|
QwtLegend* legend = new QwtLegend( plot );
|
|
plot->insertLegend( legend, QwtPlot::BottomLegend );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::setPlotData( RiaDefines::EclipseUnitSystem unitSystem,
|
|
const std::vector<RigFlowDiagDefines::RelPermCurve>& relPermCurves,
|
|
double swat,
|
|
double sgas,
|
|
const QString& caseName,
|
|
const QString& cellReferenceText,
|
|
const std::set<RiaDefines::PhaseType>& availablePhases )
|
|
{
|
|
// cvf::Trace::show("Set RelPerm plot data");
|
|
|
|
m_unitSystem = unitSystem;
|
|
m_allCurvesArr = relPermCurves;
|
|
m_swat = swat;
|
|
m_sgas = sgas;
|
|
m_caseName = caseName;
|
|
m_cellReferenceText = cellReferenceText;
|
|
m_availablePhases = availablePhases;
|
|
|
|
updateCheckboxTexts();
|
|
updatePlotOneMinusSgasCheckBoxState();
|
|
plotUiSelectedCurves();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::enableImbibitionCurveSelection( bool enable )
|
|
{
|
|
if ( !enable )
|
|
{
|
|
m_showImbibitionCheckBox->setChecked( false );
|
|
m_showImbibitionCheckBox->setDisabled( true );
|
|
}
|
|
else
|
|
{
|
|
m_showImbibitionCheckBox->setDisabled( false );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::clearPlot()
|
|
{
|
|
// cvf::Trace::show("Clear RelPerm plot data");
|
|
|
|
if ( m_allCurvesArr.empty() && m_cellReferenceText.isEmpty() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_unitSystem = RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN;
|
|
m_allCurvesArr.clear();
|
|
m_swat = HUGE_VAL;
|
|
m_sgas = HUGE_VAL;
|
|
m_caseName.clear();
|
|
m_cellReferenceText.clear();
|
|
|
|
plotCurvesInQwt( m_unitSystem,
|
|
m_allCurvesArr,
|
|
m_swat,
|
|
m_sgas,
|
|
m_cellReferenceText,
|
|
false,
|
|
true,
|
|
true,
|
|
m_qwtPlot,
|
|
&m_myPlotMarkers,
|
|
false,
|
|
false,
|
|
false,
|
|
m_availablePhases );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuRelativePermeabilityPlotUpdater* RiuRelativePermeabilityPlotPanel::plotUpdater()
|
|
{
|
|
return m_plotUpdater.get();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::applyFontSizes( bool replot /*= true*/ )
|
|
{
|
|
m_qwtPlot->applyFontSizes( replot );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::plotUiSelectedCurves()
|
|
{
|
|
std::vector<RigFlowDiagDefines::RelPermCurve> selectedCurves = gatherUiSelectedCurves();
|
|
|
|
const bool useLogScale = m_logarithmicScaleKrAxisCheckBox->isChecked();
|
|
const bool fixedXAxis = m_fixedXAxisCheckBox->isChecked();
|
|
const bool fixedYAxis = m_fixedLeftYAxisCheckBox->isChecked();
|
|
plotCurvesInQwt( m_unitSystem,
|
|
selectedCurves,
|
|
m_swat,
|
|
m_sgas,
|
|
m_cellReferenceText,
|
|
useLogScale,
|
|
fixedXAxis,
|
|
fixedYAxis,
|
|
m_qwtPlot,
|
|
&m_myPlotMarkers,
|
|
m_showScaledCheckBox->isChecked(),
|
|
m_showUnscaledCheckBox->isChecked(),
|
|
m_plotOneMinusSgasCheckBox->isChecked(),
|
|
m_availablePhases );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Add a transparent curve to make tooltip available on given points.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::addTransparentCurve( QwtPlot* plot,
|
|
const std::vector<QPointF>& points,
|
|
const std::vector<WhichYAxis>& axes,
|
|
bool logScaleLeftAxis )
|
|
{
|
|
QwtPlotCurve* curveLeftAxis = new QwtPlotCurve();
|
|
QwtPlotCurve* curveRightAxis = new QwtPlotCurve();
|
|
|
|
QVector<QPointF> pointsOnLeftAxis;
|
|
QVector<QPointF> pointsOnRightAxis;
|
|
|
|
// Each point is defined by either left or right axis
|
|
CAF_ASSERT( points.size() == axes.size() );
|
|
|
|
for ( size_t i = 0; i < points.size(); i++ )
|
|
{
|
|
if ( !RiaCurveDataTools::isValidValue( points[i].y(), logScaleLeftAxis ) ) continue;
|
|
|
|
if ( axes[i] == LEFT_YAXIS )
|
|
{
|
|
pointsOnLeftAxis.push_back( points[i] );
|
|
}
|
|
else
|
|
{
|
|
pointsOnRightAxis.push_back( points[i] );
|
|
}
|
|
}
|
|
|
|
curveLeftAxis->setSamples( pointsOnLeftAxis );
|
|
curveRightAxis->setSamples( pointsOnRightAxis );
|
|
|
|
curveLeftAxis->setYAxis( QwtAxis::YLeft );
|
|
curveRightAxis->setYAxis( QwtAxis::YRight );
|
|
|
|
curveLeftAxis->setStyle( QwtPlotCurve::NoCurve );
|
|
curveRightAxis->setStyle( QwtPlotCurve::NoCurve );
|
|
|
|
curveLeftAxis->setLegendAttribute( QwtPlotCurve::LegendNoAttribute );
|
|
curveRightAxis->setLegendAttribute( QwtPlotCurve::LegendNoAttribute );
|
|
|
|
curveLeftAxis->attach( plot );
|
|
curveRightAxis->attach( plot );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitSystem unitSystem,
|
|
const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr,
|
|
double swat,
|
|
double sgas,
|
|
QString cellReferenceText,
|
|
bool logScaleLeftAxis,
|
|
bool fixedXAxis,
|
|
bool fixedLeftYAxis,
|
|
QwtPlot* plot,
|
|
std::vector<QwtPlotMarker*>* myPlotMarkers,
|
|
bool showScaled,
|
|
bool showUnscaled,
|
|
bool plotOneMinusSgas,
|
|
const std::set<RiaDefines::PhaseType>& availablePhases )
|
|
{
|
|
bool skipUnscaledLegends = showScaled && showUnscaled;
|
|
|
|
plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
|
|
|
|
// Workaround for detaching only plot markers that we have added
|
|
// Needed as long as the curve point tracker is also using plot markers for its marking
|
|
// plot->detachItems(QwtPlotItem::Rtti_PlotMarker);
|
|
for ( QwtPlotMarker* marker : *myPlotMarkers )
|
|
{
|
|
marker->detach();
|
|
delete marker;
|
|
}
|
|
myPlotMarkers->clear();
|
|
|
|
std::vector<QPointF> points;
|
|
std::vector<WhichYAxis> axes;
|
|
|
|
const QColor waterColor = RiuGuiTheme::getColorByVariableName( "curveColorWater" );
|
|
const QColor gasColor = RiuGuiTheme::getColorByVariableName( "curveColorGas" );
|
|
|
|
// Only apply the 1-SGAS transformation for two-phase gas-water systems
|
|
const bool applyOneMinusSgas = plotOneMinusSgas && RiaPhaseTools::isTwoPhaseGasWater( availablePhases );
|
|
|
|
// Use a local, possibly saturation-transformed, copy of the curves for plotting. The same transform is also
|
|
// applied when generating the exported ascii data, see asciiDataForUiSelectedCurves(), so that the two stay in sync.
|
|
const std::vector<RigFlowDiagDefines::RelPermCurve> curvesToPlot = applyOneMinusSgasTransform( curveArr, applyOneMinusSgas );
|
|
|
|
bool shouldEnableRightYAxis = false;
|
|
|
|
for ( size_t i = 0; i < curvesToPlot.size(); i++ )
|
|
{
|
|
const RigFlowDiagDefines::RelPermCurve& curve = curvesToPlot[i];
|
|
|
|
const auto unscaledCurve = ( curve.epsMode == RigFlowDiagDefines::RelPermCurve::EPS_OFF );
|
|
|
|
// Which axis should this curve be plotted on
|
|
WhichYAxis plotOnWhichYAxis = LEFT_YAXIS;
|
|
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::PCOW || curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
|
|
{
|
|
plotOnWhichYAxis = RIGHT_YAXIS;
|
|
}
|
|
|
|
// Determine display name for the curve
|
|
std::string displayName = curve.name;
|
|
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
|
|
{
|
|
std::string preferredName;
|
|
if ( curve.curveSet == RigFlowDiagDefines::RelPermCurve::IMBIBITION )
|
|
{
|
|
preferredName += "I";
|
|
}
|
|
preferredName += RiaPhaseTools::getPreferredPcogName( availablePhases ).toStdString();
|
|
|
|
displayName = preferredName;
|
|
}
|
|
|
|
QwtPlotCurve* qwtCurve = new QwtPlotCurve( displayName.c_str() );
|
|
|
|
CAF_ASSERT( curve.saturationVals.size() == curve.yVals.size() );
|
|
qwtCurve->setSamples( curve.saturationVals.data(), curve.yVals.data(), static_cast<int>( curve.saturationVals.size() ) );
|
|
|
|
// Use the display name which may be modified for GAS/WATER cases
|
|
qwtCurve->setTitle( displayName.c_str() );
|
|
|
|
qwtCurve->setStyle( QwtPlotCurve::Lines );
|
|
|
|
auto penStyle = Qt::SolidLine;
|
|
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::PCOW || curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
|
|
{
|
|
penStyle = Qt::DashLine;
|
|
}
|
|
|
|
const QPen curvePen( QBrush(), 1, penStyle );
|
|
qwtCurve->setPen( curvePen );
|
|
|
|
auto* curveSymbol = unscaledCurve ? new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_CROSS )
|
|
: new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_ELLIPSE );
|
|
curveSymbol->setSize( 6, 6 );
|
|
curveSymbol->setBrush( Qt::NoBrush );
|
|
qwtCurve->setSymbol( curveSymbol );
|
|
|
|
qwtCurve->setLegendAttribute( QwtPlotCurve::LegendShowLine, true );
|
|
qwtCurve->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false );
|
|
qwtCurve->setLegendAttribute( QwtPlotCurve::LegendShowBrush, true );
|
|
|
|
const bool showLegend = !( unscaledCurve && skipUnscaledLegends );
|
|
qwtCurve->setItemAttribute( QwtPlotItem::Legend, showLegend );
|
|
|
|
qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
|
|
|
|
if ( plotOnWhichYAxis == RIGHT_YAXIS )
|
|
{
|
|
qwtCurve->setYAxis( { QwtAxis::YRight, 0 } );
|
|
shouldEnableRightYAxis = true;
|
|
}
|
|
|
|
qwtCurve->attach( plot );
|
|
|
|
RiuGuiTheme::styleQwtItem( qwtCurve );
|
|
|
|
// Add markers to indicate where SWAT and/or SGAS saturation intersects the respective curves
|
|
// Note that if we're using log scale we must guard against non-positive values
|
|
if ( swat != HUGE_VAL )
|
|
{
|
|
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::KRW || curve.ident == RigFlowDiagDefines::RelPermCurve::KROW ||
|
|
curve.ident == RigFlowDiagDefines::RelPermCurve::PCOW )
|
|
{
|
|
addCurveConstSaturationIntersectionMarker( curve, swat, waterColor, plotOnWhichYAxis, plot, myPlotMarkers, &points, &axes );
|
|
}
|
|
}
|
|
if ( sgas != HUGE_VAL )
|
|
{
|
|
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::KRG || curve.ident == RigFlowDiagDefines::RelPermCurve::KROG ||
|
|
curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
|
|
{
|
|
const double effectiveSgas = applyOneMinusSgas ? 1.0 - sgas : sgas;
|
|
addCurveConstSaturationIntersectionMarker( curve, effectiveSgas, gasColor, plotOnWhichYAxis, plot, myPlotMarkers, &points, &axes );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( shouldEnableRightYAxis )
|
|
{
|
|
plot->setAxesCount( QwtAxis::YRight, 1 );
|
|
plot->setAxisVisible( QwtAxis::YRight, true );
|
|
}
|
|
else
|
|
{
|
|
plot->setAxesCount( QwtAxis::YRight, 0 );
|
|
plot->setAxisVisible( QwtAxis::YRight, false );
|
|
}
|
|
|
|
addTransparentCurve( plot, points, axes, logScaleLeftAxis );
|
|
|
|
// Add vertical marker lines to indicate cell SWAT and/or SGAS saturations
|
|
if ( swat != HUGE_VAL )
|
|
{
|
|
addVerticalSaturationMarkerLine( swat, RiaResultNames::swat(), waterColor, plot, myPlotMarkers );
|
|
}
|
|
if ( sgas != HUGE_VAL )
|
|
{
|
|
const double effectiveSgas = applyOneMinusSgas ? 1.0 - sgas : sgas;
|
|
const QString sgasLabel = applyOneMinusSgas ? "1-" + RiaResultNames::sgas() : RiaResultNames::sgas();
|
|
addVerticalSaturationMarkerLine( effectiveSgas, sgasLabel, gasColor, plot, myPlotMarkers );
|
|
}
|
|
|
|
if ( logScaleLeftAxis )
|
|
{
|
|
if ( !dynamic_cast<QwtLogScaleEngine*>( plot->axisScaleEngine( QwtAxis::YLeft ) ) )
|
|
{
|
|
plot->setAxisScaleEngine( QwtAxis::YLeft, new QwtLogScaleEngine );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !dynamic_cast<QwtLinearScaleEngine*>( plot->axisScaleEngine( QwtAxis::YLeft ) ) )
|
|
{
|
|
plot->setAxisScaleEngine( QwtAxis::YLeft, new QwtLinearScaleEngine );
|
|
}
|
|
}
|
|
|
|
if ( fixedXAxis )
|
|
{
|
|
plot->setAxisScale( QwtAxis::XBottom, 0.0, 1.0 );
|
|
plot->setAxisAutoScale( QwtAxis::XBottom, false );
|
|
}
|
|
else
|
|
{
|
|
plot->setAxisAutoScale( QwtAxis::XBottom, true );
|
|
}
|
|
|
|
if ( fixedLeftYAxis )
|
|
{
|
|
if ( logScaleLeftAxis )
|
|
{
|
|
plot->setAxisScale( QwtAxis::YLeft, 1.0e-6, 1.0 );
|
|
}
|
|
else
|
|
{
|
|
plot->setAxisScale( QwtAxis::YLeft, 0.0, 1.0 );
|
|
}
|
|
plot->setAxisAutoScale( QwtAxis::YLeft, false );
|
|
}
|
|
else
|
|
{
|
|
plot->setAxisAutoScale( QwtAxis::YLeft, true );
|
|
}
|
|
|
|
if ( showScaled )
|
|
{
|
|
QwtPlotCurve* curve = getLegendCurve( "Scaled", true /*scaled*/ );
|
|
curve->attach( plot );
|
|
}
|
|
|
|
if ( showUnscaled )
|
|
{
|
|
QwtPlotCurve* curve = getLegendCurve( "Unscaled", false /*scaled*/ );
|
|
curve->attach( plot );
|
|
}
|
|
|
|
QString titleStr = "Relative Permeability";
|
|
if ( !cellReferenceText.isEmpty() )
|
|
{
|
|
titleStr += ", " + cellReferenceText;
|
|
}
|
|
plot->setTitle( titleStr );
|
|
|
|
plot->setAxisTitle( QwtAxis::XBottom, determineXAxisTitleFromCurveCollection( curveArr, applyOneMinusSgas ) );
|
|
plot->setAxisTitle( QwtAxis::YLeft, "Kr" );
|
|
plot->setAxisTitle( QwtAxis::YRight, QString( "Pc [%1]" ).arg( RiaEclipseUnitTools::unitStringPressure( unitSystem ) ) );
|
|
plot->replot();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QwtPlotCurve* RiuRelativePermeabilityPlotPanel::getLegendCurve( QString title, bool scaled )
|
|
{
|
|
QwtPlotCurve* curve = new QwtPlotCurve( title );
|
|
|
|
curve->setTitle( title );
|
|
|
|
curve->setStyle( QwtPlotCurve::Lines );
|
|
|
|
const QPen curvePen( QBrush(), 1, Qt::SolidLine );
|
|
curve->setPen( curvePen );
|
|
|
|
auto* curveSymbol = scaled ? new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_ELLIPSE ) : new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_CROSS );
|
|
curveSymbol->setSize( 6, 6 );
|
|
curveSymbol->setBrush( QBrush() );
|
|
curve->setSymbol( curveSymbol );
|
|
|
|
curve->setLegendAttribute( QwtPlotCurve::LegendShowLine, true );
|
|
curve->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, true );
|
|
curve->setLegendAttribute( QwtPlotCurve::LegendShowBrush, false );
|
|
curve->setItemAttribute( QwtPlotItem::Legend, true );
|
|
|
|
return curve;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuRelativePermeabilityPlotPanel::determineXAxisTitleFromCurveCollection( const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr,
|
|
bool plotOneMinusSgas )
|
|
{
|
|
bool sawWater = false;
|
|
bool sawGas = false;
|
|
|
|
for ( const RigFlowDiagDefines::RelPermCurve& curve : curveArr )
|
|
{
|
|
if ( curve.isWaterCurve() ) sawWater = true;
|
|
if ( curve.isGasCurve() ) sawGas = true;
|
|
}
|
|
|
|
const QString gasAxisLabel = plotOneMinusSgas ? "1-SGAS" : "SGAS";
|
|
|
|
QString title = "";
|
|
if ( sawWater && sawGas )
|
|
title = "SWAT/" + gasAxisLabel;
|
|
else if ( sawWater )
|
|
title = "SWAT";
|
|
else if ( sawGas )
|
|
title = gasAxisLabel;
|
|
|
|
return title;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns a copy of curveArr where the saturation values of the gas curves are transformed to 1-SGAS when
|
|
/// applyTransform is true. Used both when plotting the curves and when generating the exported ascii data, so
|
|
/// that the two always stay in sync.
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RigFlowDiagDefines::RelPermCurve>
|
|
RiuRelativePermeabilityPlotPanel::applyOneMinusSgasTransform( const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr,
|
|
bool applyTransform )
|
|
{
|
|
if ( !applyTransform ) return curveArr;
|
|
|
|
std::vector<RigFlowDiagDefines::RelPermCurve> transformedCurves = curveArr;
|
|
for ( RigFlowDiagDefines::RelPermCurve& curve : transformedCurves )
|
|
{
|
|
if ( !curve.isGasCurve() ) continue;
|
|
|
|
for ( double& saturationVal : curve.saturationVals )
|
|
{
|
|
saturationVal = 1.0 - saturationVal;
|
|
}
|
|
|
|
// Keep x ascending, as required by the interpolation used for the intersection markers
|
|
std::reverse( curve.saturationVals.begin(), curve.saturationVals.end() );
|
|
std::reverse( curve.yVals.begin(), curve.yVals.end() );
|
|
}
|
|
|
|
return transformedCurves;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Add a vertical labeled marker line at the specified saturation value
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::addVerticalSaturationMarkerLine( double saturationValue,
|
|
QString label,
|
|
QColor color,
|
|
QwtPlot* plot,
|
|
std::vector<QwtPlotMarker*>* myPlotMarkers )
|
|
{
|
|
QwtPlotMarker* lineMarker = new QwtPlotMarker;
|
|
lineMarker->setXValue( saturationValue );
|
|
lineMarker->setLineStyle( QwtPlotMarker::VLine );
|
|
lineMarker->setLinePen( QPen( color, 1, Qt::DotLine ) );
|
|
lineMarker->setLabel( label );
|
|
lineMarker->setLabelAlignment( Qt::AlignTop | Qt::AlignRight );
|
|
lineMarker->setLabelOrientation( Qt::Vertical );
|
|
|
|
lineMarker->attach( plot );
|
|
myPlotMarkers->push_back( lineMarker );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Add a marker at the intersection of the passed curve and the constant saturation value
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::addCurveConstSaturationIntersectionMarker( const RigFlowDiagDefines::RelPermCurve& curve,
|
|
double saturationValue,
|
|
QColor markerColor,
|
|
WhichYAxis whichYAxis,
|
|
QwtPlot* plot,
|
|
std::vector<QwtPlotMarker*>* myPlotMarkers,
|
|
std::vector<QPointF>* points,
|
|
std::vector<WhichYAxis>* axes )
|
|
{
|
|
const double yVal = RiaInterpolationTools::linear( curve.saturationVals, curve.yVals, saturationValue );
|
|
if ( yVal != HUGE_VAL )
|
|
{
|
|
QwtPlotMarker* pointMarker = new QwtPlotMarker;
|
|
pointMarker->setValue( saturationValue, yVal );
|
|
|
|
QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse );
|
|
symbol->setSize( 13, 13 );
|
|
symbol->setPen( QPen( markerColor, 2 ) );
|
|
symbol->setBrush( Qt::NoBrush );
|
|
pointMarker->setSymbol( symbol );
|
|
pointMarker->attach( plot );
|
|
|
|
if ( whichYAxis == RIGHT_YAXIS )
|
|
{
|
|
pointMarker->setYAxis( QwtAxis::YRight );
|
|
}
|
|
|
|
myPlotMarkers->push_back( pointMarker );
|
|
axes->push_back( whichYAxis );
|
|
points->push_back( QPointF( saturationValue, yVal ) );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RigFlowDiagDefines::RelPermCurve> RiuRelativePermeabilityPlotPanel::gatherUiSelectedCurves() const
|
|
{
|
|
std::vector<RigFlowDiagDefines::RelPermCurve> selectedCurves;
|
|
|
|
// Determine which curves to actually plot based on selection in GUI
|
|
const bool showScaled = m_showScaledCheckBox->isChecked();
|
|
const bool showUnscaled = m_showUnscaledCheckBox->isChecked();
|
|
const bool showDrainage = m_showDrainageCheckBox->isChecked();
|
|
const bool showImbibition = m_showImbibitionCheckBox->isChecked();
|
|
|
|
for ( size_t i = 0; i < m_allCurvesArr.size(); i++ )
|
|
{
|
|
const RigFlowDiagDefines::RelPermCurve::Ident curveIdent = m_allCurvesArr[i].ident;
|
|
const RigFlowDiagDefines::RelPermCurve::EpsMode curveEpsMode = m_allCurvesArr[i].epsMode;
|
|
const RigFlowDiagDefines::RelPermCurve::CurveSet curveSet = m_allCurvesArr[i].curveSet;
|
|
|
|
// Check if curve type is selected
|
|
const bool curveSetSelected = ( curveSet == RigFlowDiagDefines::RelPermCurve::DRAINAGE && showDrainage ) ||
|
|
( curveSet == RigFlowDiagDefines::RelPermCurve::IMBIBITION && showImbibition );
|
|
|
|
if ( curveSetSelected && m_selectedCurvesButtonGroup->button( curveIdent ) &&
|
|
m_selectedCurvesButtonGroup->button( curveIdent )->isChecked() )
|
|
{
|
|
if ( ( ( curveEpsMode == RigFlowDiagDefines::RelPermCurve::EPS_ON ) && showScaled ) ||
|
|
( ( curveEpsMode == RigFlowDiagDefines::RelPermCurve::EPS_OFF ) && showUnscaled ) )
|
|
{
|
|
selectedCurves.push_back( m_allCurvesArr[i] );
|
|
}
|
|
}
|
|
}
|
|
|
|
return selectedCurves;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuRelativePermeabilityPlotPanel::asciiDataForUiSelectedCurves() const
|
|
{
|
|
std::vector<RigFlowDiagDefines::RelPermCurve> selectedCurves = gatherUiSelectedCurves();
|
|
|
|
// Apply the same saturation transform as used when plotting, so the exported data matches the graph
|
|
const bool applyOneMinusSgas = m_plotOneMinusSgasCheckBox->isChecked() && RiaPhaseTools::isTwoPhaseGasWater( m_availablePhases );
|
|
selectedCurves = applyOneMinusSgasTransform( selectedCurves, applyOneMinusSgas );
|
|
|
|
QString outTxt;
|
|
|
|
// Info header
|
|
outTxt += m_caseName + ", " + m_cellReferenceText + "\n";
|
|
|
|
// Column headers
|
|
for ( size_t icurve = 0; icurve < selectedCurves.size(); icurve++ )
|
|
{
|
|
if ( icurve > 0 ) outTxt += "\t";
|
|
|
|
const RigFlowDiagDefines::RelPermCurve& curve = selectedCurves[icurve];
|
|
|
|
if ( curve.isWaterCurve() )
|
|
outTxt += "SWAT";
|
|
else if ( curve.isGasCurve() )
|
|
outTxt += applyOneMinusSgas ? "1-SGAS" : "SGAS";
|
|
else
|
|
outTxt += "Saturation";
|
|
outTxt += "\t";
|
|
outTxt += curve.name.c_str();
|
|
}
|
|
|
|
// Table data
|
|
size_t sampleIndex = 0;
|
|
bool iterationContributedData = true;
|
|
while ( iterationContributedData )
|
|
{
|
|
iterationContributedData = false;
|
|
|
|
QString lineStr = "\n";
|
|
|
|
for ( size_t icurve = 0; icurve < selectedCurves.size(); icurve++ )
|
|
{
|
|
if ( icurve > 0 ) lineStr += "\t";
|
|
|
|
const RigFlowDiagDefines::RelPermCurve& curve = selectedCurves[icurve];
|
|
if ( sampleIndex < curve.saturationVals.size() && sampleIndex < curve.yVals.size() )
|
|
{
|
|
lineStr += QString::number( curve.saturationVals[sampleIndex], 'g', 6 );
|
|
lineStr += "\t";
|
|
lineStr += QString::number( curve.yVals[sampleIndex], 'g', 6 );
|
|
|
|
iterationContributedData = true;
|
|
}
|
|
else
|
|
{
|
|
lineStr += "\t";
|
|
}
|
|
}
|
|
|
|
if ( iterationContributedData )
|
|
{
|
|
outTxt += lineStr;
|
|
}
|
|
|
|
sampleIndex++;
|
|
}
|
|
|
|
return outTxt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::updateCheckboxTexts()
|
|
{
|
|
// Update PCOG checkbox text to PCGW for GAS/WATER cases
|
|
if ( auto button = m_selectedCurvesButtonGroup->button( RigFlowDiagDefines::RelPermCurve::PCOG ) )
|
|
{
|
|
QString preferredName = RiaPhaseTools::getPreferredPcogName( m_availablePhases );
|
|
button->setText( preferredName );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Only allow the "Plot 1-SGAS" option for two-phase gas-water systems
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::updatePlotOneMinusSgasCheckBoxState()
|
|
{
|
|
const bool enable = RiaPhaseTools::isTwoPhaseGasWater( m_availablePhases );
|
|
if ( !enable )
|
|
{
|
|
m_plotOneMinusSgasCheckBox->setChecked( false );
|
|
}
|
|
m_plotOneMinusSgasCheckBox->setEnabled( enable );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::contextMenuEvent( QContextMenuEvent* event )
|
|
{
|
|
QMenu menu;
|
|
|
|
const int curveCount = m_qwtPlot->itemList( QwtPlotItem::Rtti_PlotCurve ).count();
|
|
|
|
QAction* act = menu.addAction( "Show Plot Data", this, SLOT( slotCurrentPlotDataInTextDialog() ) );
|
|
act->setEnabled( curveCount > 0 );
|
|
|
|
menu.exec( event->globalPos() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::slotCurrentPlotDataInTextDialog()
|
|
{
|
|
QString outTxt = asciiDataForUiSelectedCurves();
|
|
|
|
RiuTextDialog* textDialog = new RiuTextDialog( this );
|
|
textDialog->setMinimumSize( 400, 600 );
|
|
textDialog->setWindowTitle( "Relative Permeability Data" );
|
|
textDialog->setText( outTxt );
|
|
textDialog->show();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::slotShowCurveSelectionWidgets( int state )
|
|
{
|
|
bool setVisible = ( state != Qt::CheckState::Unchecked );
|
|
|
|
m_groupBox->setVisible( setVisible );
|
|
m_showUnscaledCheckBox->setVisible( setVisible );
|
|
m_showScaledCheckBox->setVisible( setVisible );
|
|
m_logarithmicScaleKrAxisCheckBox->setVisible( setVisible );
|
|
m_fixedXAxisCheckBox->setVisible( setVisible );
|
|
m_fixedLeftYAxisCheckBox->setVisible( setVisible );
|
|
m_plotOneMinusSgasCheckBox->setVisible( setVisible );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::slotButtonInButtonGroupClicked( int )
|
|
{
|
|
plotUiSelectedCurves();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::slotSomeCheckBoxStateChanged( int )
|
|
{
|
|
plotUiSelectedCurves();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::showEvent( QShowEvent* event )
|
|
{
|
|
if ( m_plotUpdater != nullptr ) m_plotUpdater->doDelayedUpdate();
|
|
QWidget::showEvent( event );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::slotPickerPointChanged( const QPoint& pt )
|
|
{
|
|
updateTrackerPlotMarkerAndLabelFromPicker();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::slotPickerActivated( bool on )
|
|
{
|
|
updateTrackerPlotMarkerAndLabelFromPicker();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuRelativePermeabilityPlotPanel::updateTrackerPlotMarkerAndLabelFromPicker()
|
|
{
|
|
bool hasValidSamplePoint = false;
|
|
QPointF samplePoint;
|
|
QString curveTitle = "";
|
|
|
|
if ( m_qwtPicker && m_qwtPicker->isActive() )
|
|
{
|
|
const QPoint trackerPos = m_qwtPicker->trackerPosition();
|
|
|
|
int pointSampleIdx = -1;
|
|
const QwtPlotCurve* closestQwtCurve = closestCurveSample( trackerPos, &pointSampleIdx );
|
|
if ( closestQwtCurve && pointSampleIdx >= 0 )
|
|
{
|
|
samplePoint = closestQwtCurve->sample( pointSampleIdx );
|
|
hasValidSamplePoint = true;
|
|
curveTitle = closestQwtCurve->title().text();
|
|
}
|
|
}
|
|
|
|
m_trackerLabel = "";
|
|
|
|
bool needsReplot = false;
|
|
|
|
if ( hasValidSamplePoint )
|
|
{
|
|
if ( !m_trackerPlotMarker )
|
|
{
|
|
m_trackerPlotMarker = new QwtPlotMarker;
|
|
m_trackerPlotMarker->setTitle( QString( "TrackedPoint" ) );
|
|
|
|
QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse );
|
|
symbol->setSize( 13, 13 );
|
|
symbol->setBrush( Qt::NoBrush );
|
|
m_trackerPlotMarker->setSymbol( symbol );
|
|
m_trackerPlotMarker->attach( m_qwtPlot );
|
|
RiuGuiTheme::styleQwtItem( m_trackerPlotMarker );
|
|
|
|
needsReplot = true;
|
|
}
|
|
|
|
if ( m_trackerPlotMarker->value() != samplePoint )
|
|
{
|
|
m_trackerPlotMarker->setValue( samplePoint );
|
|
needsReplot = true;
|
|
}
|
|
|
|
m_trackerLabel = QString( "%1: (%2, %3)" ).arg( curveTitle ).arg( samplePoint.x(), 0, 'f', 3 ).arg( samplePoint.y(), 0, 'f', 3 );
|
|
}
|
|
else
|
|
{
|
|
if ( m_trackerPlotMarker )
|
|
{
|
|
m_trackerPlotMarker->detach();
|
|
delete m_trackerPlotMarker;
|
|
m_trackerPlotMarker = nullptr;
|
|
|
|
needsReplot = true;
|
|
}
|
|
}
|
|
|
|
if ( needsReplot )
|
|
{
|
|
m_qwtPlot->replot();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const QwtPlotCurve* RiuRelativePermeabilityPlotPanel::closestCurveSample( const QPoint& cursorPosition, int* closestSampleIndex ) const
|
|
{
|
|
if ( !m_qwtPlot ) return nullptr;
|
|
|
|
// Get all curves currently attached to the plot
|
|
const QwtPlotItemList& plotItems = m_qwtPlot->itemList( QwtPlotItem::Rtti_PlotCurve );
|
|
|
|
double minDistSquared = std::numeric_limits<double>::max();
|
|
const QwtPlotCurve* closestCurve = nullptr;
|
|
int closestPtIdx = -1;
|
|
|
|
for ( auto plotItem : plotItems )
|
|
{
|
|
const QwtPlotCurve* candidateCurve = dynamic_cast<const QwtPlotCurve*>( plotItem );
|
|
if ( !candidateCurve || !candidateCurve->isVisible() ) continue;
|
|
|
|
for ( size_t ptIdx = 0; ptIdx < candidateCurve->dataSize(); ptIdx++ )
|
|
{
|
|
QPointF samplePoint = candidateCurve->sample( static_cast<int>( ptIdx ) );
|
|
QPoint screenPoint = QPoint( m_qwtPlot->transform( candidateCurve->xAxis(), samplePoint.x() ),
|
|
m_qwtPlot->transform( candidateCurve->yAxis(), samplePoint.y() ) );
|
|
|
|
double distSquared = pow( screenPoint.x() - cursorPosition.x(), 2 ) + pow( screenPoint.y() - cursorPosition.y(), 2 );
|
|
|
|
if ( distSquared < minDistSquared )
|
|
{
|
|
minDistSquared = distSquared;
|
|
closestCurve = candidateCurve;
|
|
closestPtIdx = static_cast<int>( ptIdx );
|
|
}
|
|
}
|
|
}
|
|
|
|
const double maxAllowedDistanceSquared = 20.0 * 20.0; // 20 pixels
|
|
if ( minDistSquared <= maxAllowedDistanceSquared )
|
|
{
|
|
if ( closestSampleIndex ) *closestSampleIndex = closestPtIdx;
|
|
return closestCurve;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|