mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Implement stacked well log curves
This commit is contained in:
@@ -165,11 +165,14 @@ void RimWellFlowRateCurve::onLoadDataAndUpdate( bool updateParentPlot )
|
||||
{
|
||||
m_qwtPlotCurve->setTitle( createCurveAutoName() );
|
||||
|
||||
if ( updateParentPlot )
|
||||
{
|
||||
RimWellLogTrack* track = nullptr;
|
||||
this->firstAncestorOrThisOfTypeAsserted( track );
|
||||
track->updateStackedCurveData();
|
||||
|
||||
updateZoomInParentPlot();
|
||||
}
|
||||
|
||||
if ( m_parentQwtPlot ) m_parentQwtPlot->replot();
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ RimPlotAxisProperties::RimPlotAxisProperties()
|
||||
CAF_PDM_InitField(&m_isAutoZoom, "AutoZoom", true, "Set Range Automatically", "", "", "");
|
||||
CAF_PDM_InitField(&isLogarithmicScaleEnabled, "LogarithmicScale", false, "Logarithmic Scale", "", "", "");
|
||||
CAF_PDM_InitField(&m_isAxisInverted, "AxisInverted", false, "Invert Axis", "", "", "");
|
||||
CAF_PDM_InitField(&m_stackCurves, "StackCurves", false, "Stack Curves", "", "", "");
|
||||
|
||||
CAF_PDM_InitFieldNoDefault(&m_titlePositionEnum, "TitlePosition", "Title Position", "", "", "");
|
||||
|
||||
@@ -187,6 +188,7 @@ void RimPlotAxisProperties::defineUiOrdering( QString uiConfigName, caf::PdmUiOr
|
||||
scaleGroup.add( &isLogarithmicScaleEnabled );
|
||||
scaleGroup.add( &m_isAxisInverted );
|
||||
}
|
||||
scaleGroup.add( &m_stackCurves );
|
||||
scaleGroup.add( &numberFormat );
|
||||
|
||||
if ( numberFormat() != NUMBER_FORMAT_AUTO )
|
||||
@@ -347,6 +349,14 @@ void RimPlotAxisProperties::setAxisInverted( bool inverted )
|
||||
m_isAxisInverted = inverted;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimPlotAxisProperties::stackCurves() const
|
||||
{
|
||||
return m_stackCurves();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -399,7 +409,7 @@ void RimPlotAxisProperties::fieldChangedByUi( const caf::PdmFieldHandle* changed
|
||||
this->firstAncestorOrThisOfType( parentPlot );
|
||||
if ( parentPlot )
|
||||
{
|
||||
if ( changedField == &isLogarithmicScaleEnabled )
|
||||
if ( changedField == &isLogarithmicScaleEnabled || changedField == &m_stackCurves )
|
||||
{
|
||||
parentPlot->loadDataAndUpdate();
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
void setAutoZoom( bool enableAutoZoom );
|
||||
bool isAxisInverted() const;
|
||||
void setAxisInverted( bool inverted );
|
||||
bool stackCurves() const;
|
||||
|
||||
std::vector<RimPlotAxisAnnotation*> annotations() const;
|
||||
void appendAnnotation( RimPlotAxisAnnotation* annotation );
|
||||
@@ -114,6 +115,7 @@ private:
|
||||
caf::PdmField<bool> m_displayUnitText;
|
||||
caf::PdmField<bool> m_isAutoZoom;
|
||||
caf::PdmField<bool> m_isAxisInverted;
|
||||
caf::PdmField<bool> m_stackCurves;
|
||||
|
||||
caf::PdmField<QString> m_name;
|
||||
QwtPlot::Axis m_axis;
|
||||
|
||||
@@ -40,5 +40,3 @@ void RimPlotAxisPropertiesInterface::LegendTickmarkCountEnum::setUp()
|
||||
setDefault( RimPlotAxisPropertiesInterface::LegendTickmarkCount::TICKMARK_DEFAULT );
|
||||
}
|
||||
} // namespace caf
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "RimPlotCurve.h"
|
||||
|
||||
#include "RiaColorTools.h"
|
||||
#include "RiaCurveDataTools.h"
|
||||
#include "RiaGuiApplication.h"
|
||||
#include "RiaPreferences.h"
|
||||
@@ -770,7 +771,7 @@ void RimPlotCurve::updateCurveAppearance()
|
||||
if ( m_qwtPlotCurve )
|
||||
{
|
||||
QColor fillColor( m_fillColor.value().rByte(), m_fillColor.value().gByte(), m_fillColor.value().bByte() );
|
||||
fillColor.setAlpha( 130 );
|
||||
fillColor = RiaColorTools::blendQColors( fillColor, QColor( Qt::white ), 3, 1 );
|
||||
QBrush fillBrush( fillColor, m_fillStyle() );
|
||||
m_qwtPlotCurve->setAppearance( m_lineStyle(), m_curveInterpolation(), m_curveThickness(), curveColor, fillBrush );
|
||||
m_qwtPlotCurve->setSymbol( symbol );
|
||||
@@ -983,6 +984,22 @@ void RimPlotCurve::resetAppearance()
|
||||
setSymbolSkipDistance( 10 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Qt::BrushStyle RimPlotCurve::fillStyle() const
|
||||
{
|
||||
return m_fillStyle();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimPlotCurve::setFillStyle( Qt::BrushStyle brushStyle )
|
||||
{
|
||||
m_fillStyle = brushStyle;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -80,6 +80,8 @@ public:
|
||||
void setSymbolSize( int sizeInPixels );
|
||||
void setLineThickness( int thickness );
|
||||
void resetAppearance();
|
||||
Qt::BrushStyle fillStyle() const;
|
||||
void setFillStyle( Qt::BrushStyle brushStyle );
|
||||
|
||||
bool isCurveVisible() const;
|
||||
void setCurveVisibility( bool visible );
|
||||
|
||||
@@ -460,6 +460,7 @@ void RimWellLogTrack::calculateYZoomRange()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogTrack::updateXZoom()
|
||||
{
|
||||
const double eps = 1.0e-8;
|
||||
if ( !m_plotWidget ) return;
|
||||
|
||||
calculateXZoomRange();
|
||||
@@ -469,6 +470,13 @@ void RimWellLogTrack::updateXZoom()
|
||||
m_visibleXRangeMin = m_availableXRangeMin;
|
||||
m_visibleXRangeMax = m_availableXRangeMax;
|
||||
|
||||
// Consider auto zooming to full range [0..1] range
|
||||
if ( -eps < m_visibleXRangeMin && m_visibleXRangeMin < 0.25 && 0.75 < m_visibleXRangeMax &&
|
||||
m_visibleXRangeMax < 1.0 + eps && !m_isLogarithmicScaleEnabled )
|
||||
{
|
||||
m_visibleXRangeMin = 0.0;
|
||||
m_visibleXRangeMax = 1.0;
|
||||
}
|
||||
computeAndSetXRangeMinForLogarithmicScale();
|
||||
updateEditors();
|
||||
}
|
||||
@@ -709,6 +717,25 @@ void RimWellLogTrack::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
|
||||
updateParentLayout();
|
||||
RiuPlotMainWindowTools::refreshToolbars();
|
||||
}
|
||||
else if ( changedField == &m_stackCurves )
|
||||
{
|
||||
updateStackedCurveData();
|
||||
|
||||
m_isAutoScaleXEnabled = true;
|
||||
updateXZoom();
|
||||
m_plotWidget->scheduleReplot();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogTrack::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
|
||||
{
|
||||
if ( m_stackCurves )
|
||||
{
|
||||
updateStackedCurveData();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -2081,6 +2108,7 @@ void RimWellLogTrack::uiOrderingForXAxisSettings( caf::PdmUiOrdering& uiOrdering
|
||||
gridGroup->add( &m_visibleXRangeMin );
|
||||
gridGroup->add( &m_visibleXRangeMax );
|
||||
gridGroup->add( &m_xAxisGridVisibility );
|
||||
gridGroup->add( &m_stackCurves );
|
||||
|
||||
// TODO Revisit if these settings are required
|
||||
// See issue https://github.com/OPM/ResInsight/issues/4367
|
||||
@@ -2258,6 +2286,8 @@ std::vector<QString> RimWellLogTrack::formationNamesVector( RimCase* rimCase )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogTrack::updateStackedCurveData()
|
||||
{
|
||||
const double eps = 1.0e-8;
|
||||
|
||||
RimWellLogPlot* wellLogPlot;
|
||||
firstAncestorOrThisOfTypeAsserted( wellLogPlot );
|
||||
|
||||
@@ -2270,6 +2300,13 @@ void RimWellLogTrack::updateStackedCurveData()
|
||||
reverseOrder = true;
|
||||
}
|
||||
|
||||
// Reset all curves
|
||||
for ( auto curve : visibleCurves() )
|
||||
{
|
||||
curve->loadDataAndUpdate( false );
|
||||
}
|
||||
|
||||
// Stack the curves that are meant to be stacked
|
||||
std::map<int, std::vector<RimWellLogCurve*>> stackedCurves = visibleStackedCurves();
|
||||
|
||||
for ( auto groupCurvePair : stackedCurves )
|
||||
@@ -2299,8 +2336,8 @@ void RimWellLogTrack::updateStackedCurveData()
|
||||
auto it = std::lower_bound( allDepthValues.begin(),
|
||||
allDepthValues.end(),
|
||||
depth,
|
||||
[reverseOrder]( double lhs, double rhs ) {
|
||||
return reverseOrder ? rhs < lhs : lhs < rhs;
|
||||
[eps, reverseOrder]( double lhs, double rhs ) {
|
||||
return reverseOrder ? lhs - rhs > eps : rhs - lhs > eps;
|
||||
} );
|
||||
|
||||
// Insert if there is no larger or equal depths or if the first equal or if it actually larger.
|
||||
@@ -2331,6 +2368,12 @@ void RimWellLogTrack::updateStackedCurveData()
|
||||
auto plotDepthValues = tempCurveData.depthPlotValues( depthType, displayUnit );
|
||||
auto polyLineStartStopIndices = tempCurveData.polylineStartStopIndices();
|
||||
|
||||
// Apply a area filled style if it isn't already set
|
||||
if ( curve->fillStyle() == Qt::NoBrush )
|
||||
{
|
||||
curve->setFillStyle( Qt::SolidPattern );
|
||||
}
|
||||
|
||||
curve->setOverrideCurveData( allStackedValues, plotDepthValues, polyLineStartStopIndices );
|
||||
curve->setZOrder( zPos );
|
||||
zPos -= 1.0;
|
||||
|
||||
@@ -250,6 +250,7 @@ private:
|
||||
void doRemoveFromCollection() override;
|
||||
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override;
|
||||
|
||||
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
|
||||
bool* useOptionsOnly ) override;
|
||||
|
||||
@@ -338,6 +338,43 @@ const std::vector<time_t>& RimSummaryCurve::timeStepsY() const
|
||||
return reader->timeSteps( addr );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimSummaryCurve::yValueAtTimeT( time_t time ) const
|
||||
{
|
||||
const std::vector<time_t>& timeSteps = timeStepsY();
|
||||
const std::vector<double> values = valuesY();
|
||||
|
||||
if ( timeSteps.empty() || time < timeSteps.front() || time > timeSteps.back() )
|
||||
return std::numeric_limits<double>::infinity();
|
||||
|
||||
for ( size_t i = 0; i < timeSteps.size(); ++i )
|
||||
{
|
||||
if ( timeSteps[i] == time )
|
||||
{
|
||||
return values[i];
|
||||
}
|
||||
else if ( i < timeSteps.size() - 1u && timeSteps[i] < time && time < timeSteps[i + 1] )
|
||||
{
|
||||
if ( m_curveInterpolation == RiuQwtPlotCurve::INTERPOLATION_STEP_LEFT )
|
||||
{
|
||||
return values[i + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
double slope = 0.0;
|
||||
if ( timeSteps[i + 1] != timeSteps[i] )
|
||||
{
|
||||
slope = ( values[i + 1] - values[i] ) / (double)( timeSteps[i + 1] - timeSteps[i] );
|
||||
}
|
||||
return slope * ( time - timeSteps[i] ) + values[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
void setLeftOrRightAxisY( RiaDefines::PlotAxis plotAxis );
|
||||
RiaDefines::PlotAxis axisY() const;
|
||||
const std::vector<time_t>& timeStepsY() const;
|
||||
double yValueAtTimeT( time_t time ) const;
|
||||
|
||||
// X Axis functions
|
||||
void setSummaryCaseX( RimSummaryCase* sumCase );
|
||||
|
||||
@@ -1333,6 +1333,71 @@ void RimSummaryPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimSummaryPlot::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
|
||||
{
|
||||
updateStackedCurveData();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimSummaryPlot::updateStackedCurveData()
|
||||
{
|
||||
if ( m_leftYAxisProperties->stackCurves() ) updateStackedCurveDataForAxis( RiaDefines::PlotAxis::PLOT_AXIS_LEFT );
|
||||
if ( m_rightYAxisProperties->stackCurves() ) updateStackedCurveDataForAxis( RiaDefines::PlotAxis::PLOT_AXIS_RIGHT );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimSummaryPlot::updateStackedCurveDataForAxis( RiaDefines::PlotAxis plotAxis )
|
||||
{
|
||||
// Reset all curves
|
||||
for ( RimSummaryCurve* curve : visibleSummaryCurvesForAxis( plotAxis ) )
|
||||
{
|
||||
curve->loadDataAndUpdate( false );
|
||||
}
|
||||
|
||||
RimPlotAxisProperties* axisProperties = yAxisPropertiesLeftOrRight( plotAxis );
|
||||
if ( axisProperties->stackCurves() )
|
||||
{
|
||||
// Z-position of curve, to draw them in correct order
|
||||
double zPos = -10000.0;
|
||||
|
||||
std::vector<time_t> allTimeSteps;
|
||||
for ( RimSummaryCurve* curve : visibleSummaryCurvesForAxis( plotAxis ) )
|
||||
{
|
||||
allTimeSteps.insert( allTimeSteps.end(), curve->timeStepsY().begin(), curve->timeStepsY().end() );
|
||||
}
|
||||
std::sort( allTimeSteps.begin(), allTimeSteps.end() );
|
||||
allTimeSteps.erase( std::unique( allTimeSteps.begin(), allTimeSteps.end() ), allTimeSteps.end() );
|
||||
|
||||
std::vector<double> allStackedValues( allTimeSteps.size(), 0.0 );
|
||||
for ( RimSummaryCurve* curve : visibleSummaryCurvesForAxis( plotAxis ) )
|
||||
{
|
||||
for ( size_t i = 0; i < allTimeSteps.size(); ++i )
|
||||
{
|
||||
double value = curve->yValueAtTimeT( allTimeSteps[i] );
|
||||
if ( value != std::numeric_limits<double>::infinity() )
|
||||
{
|
||||
allStackedValues[i] += value;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply a area filled style if it isn't already set
|
||||
if ( curve->fillStyle() == Qt::NoBrush )
|
||||
{
|
||||
curve->setFillStyle( Qt::SolidPattern );
|
||||
}
|
||||
curve->setOverrideCurveDataY( allTimeSteps, allStackedValues );
|
||||
curve->setZOrder( zPos );
|
||||
zPos -= 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -193,6 +193,10 @@ protected:
|
||||
// Overridden PDM methods
|
||||
caf::PdmFieldHandle* userDescriptionField() override;
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override;
|
||||
void updateStackedCurveData();
|
||||
void updateStackedCurveDataForAxis( RiaDefines::PlotAxis plotAxis );
|
||||
|
||||
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void onLoadDataAndUpdate() override;
|
||||
|
||||
@@ -336,8 +336,6 @@ void RigWellLogCurveData::interpolateSegment( RiaDefines::DepthTypeEnum resampli
|
||||
|
||||
size_t secondIndex = firstIndex + 1;
|
||||
|
||||
if ( secondIndex >= depthIt->second.size() ) return;
|
||||
|
||||
double depth0 = depthIt->second[firstIndex];
|
||||
double depth1 = depthIt->second[secondIndex];
|
||||
double x0 = m_xValues[firstIndex];
|
||||
@@ -381,7 +379,6 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
|
||||
|
||||
std::vector<double> xValues;
|
||||
|
||||
bool isTVDAvailable = false;
|
||||
std::map<RiaDefines::DepthTypeEnum, std::vector<double>> resampledDepths;
|
||||
|
||||
auto depthIt = m_depths.find( resamplingDepthType );
|
||||
@@ -393,18 +390,21 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
|
||||
bool reverseOrder = resamplingDepthType == RiaDefines::DepthTypeEnum::CONNECTION_NUMBER;
|
||||
|
||||
size_t segmentSearchStartIdx = 0;
|
||||
for ( double depth : depths )
|
||||
for ( auto depth : depths )
|
||||
{
|
||||
bool foundPoint = false;
|
||||
if ( isLeftOf( depth, depthIt->second.front(), reverseOrder, eps ) )
|
||||
{
|
||||
// Extrapolate from front two
|
||||
interpolateSegment( resamplingDepthType, depth, 0, xValues, resampledDepths, eps );
|
||||
foundPoint = true;
|
||||
}
|
||||
else if ( isLeftOf( depthIt->second.back(), depth, reverseOrder, eps ) )
|
||||
{
|
||||
// Extrapolate from end two
|
||||
const size_t N = depthIt->second.size() - 1;
|
||||
interpolateSegment( resamplingDepthType, depth, N - 1, xValues, resampledDepths, eps );
|
||||
foundPoint = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -424,6 +424,8 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
|
||||
}
|
||||
}
|
||||
segmentSearchStartIdx = segmentStartIdx + 1;
|
||||
foundPoint = true;
|
||||
break;
|
||||
}
|
||||
else if ( segmentStartIdx < depthIt->second.size() - 1 &&
|
||||
isLeftOf( depthIt->second[segmentStartIdx], depth, reverseOrder, eps ) &&
|
||||
@@ -433,9 +435,12 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
|
||||
{
|
||||
interpolateSegment( resamplingDepthType, depth, segmentStartIdx, xValues, resampledDepths, eps );
|
||||
segmentSearchStartIdx = segmentStartIdx;
|
||||
foundPoint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CAF_ASSERT( foundPoint );
|
||||
}
|
||||
|
||||
resampledDepths.insert( std::make_pair( resamplingDepthType, depths ) );
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "cafAssert.h"
|
||||
#include "cafPdmBase.h"
|
||||
#include "cafSignalHandle.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
@@ -19,7 +20,7 @@ class PdmChildArrayFieldHandle;
|
||||
//==================================================================================================
|
||||
/// The base class of all objects
|
||||
//==================================================================================================
|
||||
class PdmObjectHandle
|
||||
class PdmObjectHandle : public SignalObserver
|
||||
{
|
||||
public:
|
||||
PdmObjectHandle();
|
||||
|
||||
Reference in New Issue
Block a user